Total Pageviews

Sunday, 7 October 2018

用 Systemd管理你的linux系统

从本文开始,将对Systemd 与系统的方方面面相关的作用和功能进行详细介绍,除去基础概念以及注意事项,部分小节包含实例已帮助您理解。
再次提醒,由于个人水平和能力有限,对某些小节未能深入详细的叙述和论证,若您需要深入了解相关内容请参考对应小节参考链接,或需求其他资料。

规范化的配置文件

在Systemd 中定义了一批公用配置文件,systemd 希望通过推广和使用这些配置文件,在Linux 的各类发行版中形成标准,以解决目前各大发行版配置文件五花八门的情况。
配置文件列表:
  • /etc/hostname: 主机名。在不同的发行版上主机名存在不同的文件中,例如Fedora:/etc/sysconfig/network,OpenSUSE:/etc/HOSTNAME。systemd采用的是debian的配置文件:/etc/hostname。
  • /etc/vconsole.conf: 默认键盘映射与终端字体配置。
  • /etc/locale.conf: 配置系统全局locale。
  • /etc/modules-load/*.conf: 启动时候静态加载内核模块的配置。
  • /etc/sysctl.d/*.conf: 内核sysctl参数配置,此处配置文件作为/etc/sysctl.conf的扩展。
  • /etc/tmpfiles.d/*.conf: 临时文件的创建、删除、清空的配置。
  • /etc/binfmt.d/*.conf: 系统附加二进制格式支持的配置。
  • /etc/os-release: 包含操作系统基础信息,例如操作系统名称,版本,主页等等。(注:debian 7已存在此文件,格式相同)。
    • 例(debian testing x86)
 PRETTY_NAME="Debian GNU/Linux jessie/sid"  
 NAME="Debian GNU/Linux"  
 ID=debian  
 HOME_URL="http://www.debian.org/"
 SUPPORT_URL="http://www.debian.org/support/"
 BUG_REPORT_URL="http://bugs.debian.org/"

注: systemd 215之后,`/etc/os-release`被移到`/usr/lib/os-release`,原来的`/etc/os-release`将是后者的软链接。     
  • /etc/machine-id:机器ID。详细信息在后文Unique Machinehandling ID一节详细介绍。
  • /etc/machine-info:包含机器元数据,主要是主机名,图标名称和图片等等。详细信息在后文Dynamic host name and machine meta data handling一节详细介绍。

/etc/hostname

systemd定义的/etc/hostname 文件参考自发行版debian,路径与文件名称、格式等等与debian相同。
注:debian中的/etc/debian_version 文件依旧存在且无变化。

/etc/locale.conf

系统启用systemd之后,要设置整个系统使用的locale,只需在/etc/locale.conf 中设置LANG变量即可。 locale.conf中可以设置一系列环境变量,每行一个。可以包含LANG变量和LC_ALL外的所有LC_*变量。 例:
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
systemd提供了localectl工具用于修改系统全局locale,可以通过此工具修改locale.conf
#localectl set-locale LANG="en_US.UTF-8"
参考: man localectl
注:/etc/locale.conf默认不存在,需要手动创建。

本节参考链接:

PAM integration

systemd 提供了一个pam模块(pam_systemd.so)配合systemd 登录管理器(systemd-logind.service)用于管理用户会话,pam_systemd.so模块目前只支持session,处理系统为用户提供服务之前/后需要的做的事情,具体见下文。
pam_systemd.so支持的选项:
  • class=[user,greeter,lock-screen]:指定会话类别。
  • type =[unspecified,tty,x11,wayland,mir]:指定会话类型。
  • debug[=]:配置为yes或未配置该选项,将输出额外的调试信息。
用户登入后本模块动作:
  1. 若登入的用户的主目录不存在,将先创建所有权为登入用户的目录(/run/user/$USER),然后登入。
  2. 初始化 $XDG_SESSION_ID 环境变量。
  3. 为本次会话创建一个新的systemd scope单元(scope 单元可用来组织进程,应用资源单元,或者杀死进程组),一个用户会话的所有进程都包含在一个scope单元的实例。 若当前会话是登入用户的首次会话,一个新的slice单元user.slice(slice 单元用于将管理进程的单元分组成层级,层级可允许控制分配给 slice 的资源。) 将自动创建,每个会话将限制在用户slice 内的 scope 单元中。
用户登出后本模块动作:
1. 关闭本次会话内的所有进程。若退出会话是该用户最后一个会话,那么该用户的systemd实例也将被关闭。 - 注:nohup 和screen 运行的服务不受影响 2. 若退出的会话是该用户最后一个会话,$XDG_RUNTIME_DIR目录与其内容将被删除。

本节参考链接

Target

注:此部分内容与启动分析一节有重叠,但是考虑到本大节内容的完整性,未删去。
target单元为其他配置单元进行逻辑组,它们实际上不做什么,只是运用其他配置单元(类似快照单元),这样并可以对配置单元做一个统一的控制,这样就可以实现runlevel的概念。
启动级别(runlevel)是一个旧的概念。现在,systemd 引入了一个和启动级别功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每个目标都有名字和独特的功能,并且能同时启用多个。一些目标继承其他目标的服务,并启动新服务。systemd 提供了一些模仿 sysvinit 启动级别的目标,仍可以使用旧的 telinit 启动级别 命令切换。 ---Archlinux Wiki
它们本身实际上并不做什么,只是引用其他 unit(unit是systemd的配置单元,包含.service,.mount,.scokets等)而已。这样便可以对 unit 做一个统一的控制。(例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别5);bluetooth.target 只有在蓝牙适配器可用的情况下才调用与蓝牙相关的服务,如:bluetooth 守护进程、obex 守护进程等) - -
更多介绍:
对于常见的runlevel:0,1,2,3,4,5,6,systemd都有对应的target与之对应,不同的target与不同的服务相关,启动时候进入默认的target,即可带起下属的服务。-Fedora Wiki
target table:
由上表可知每个SvsV的启动级别与之对于的Systemd target,另外systemd一般还会有一个默认的target(default.target),default.target是上表中的某一个target的软链接,表示默认的启动级别,等同于/etc/inittab文件中的 initdefault值。
相对于/etc/rc[0~6].d,Systemd采用target来管理不同的服务,同时也是对服务进行抽象和分组管理的一种方式。除了以上表中的target,还有不同的target。例如graphical.target 依赖着multi-user.target,multi-user.target依赖着 basic.target,basic.target依赖着 sysinit.target。
可以很方便的将系统某个运行状态所需要的配置单元组合一个target进行管理。

实例

如果我们添加了一个服务(example.service),然后想此服务在系统进入多用户模式时候(multi-user.target)可以自动启动,我们可新建一个与此服务同名的target(example.target),然后ln -smulti-user.target.wants文件夹中即可。另外也可以继承已有的target,并添加其他服务,来创建自定义的target。
注:wants目录与target相关联,若一个target有同名的wants目录,只需将依赖此target的单元文件链接到目录下,当系统启动此target时同时也会自动启动这些单元文件。使用systemctl enable xxx.service,会自动根据[Install]中 WantedBy的信息创建链接文件到对应wants目录。

Path­based Activation(inotify)

systemd提供了一个以.path为扩展名的单元,用于监视目录文件,激活服务。由于path单元内部使用inotify的API监视文件系统,所以也和inotify具有同样的局限性,无法用于监视远程NFS文件系统上的文件或目录。
每一个path单元默认必须有一个同名的service单元,path单元监视文件或目录去激活同名的service服务(可以通过Unit选项指定激活的单元)。 触发条件的选项:
  • PathExists=:目录或文件存在时,触发service单元;
  • PathExistsGlob=:和PathExists类似,不过可以使用通配符指定监视的目录和文件们,当至少有一个文件或目录存在时,触发service单元。
  • PathCahnged=:目录或文件在打开后再关闭的时候如果发生了更改将触发service单元,打开和关闭文件期间的写和变动不会触发服务。
  • PathModified=:目录或文件每一次更改都会触发service单元。
  • DirectoryNotEmpty=:目录非空时,触发service单元。

实例

为了确保当有打印任务在队列中的时候CUPS服务(UNIX 通用打印系统)会启动,我们可以写一个cups.path:当在/var/spool/cups目录下发现文件时,激活CUPS服务(存在同名服务单元cups.service)。
[Unit]
Description=CUPS Printer Service Spool

[Path]
DirectoryNotEmpty=/var/spool/cups

[Install]
WantedBy=multi-user.target
例子来源:systemd for Developers II#Path-based Activation in Detail
注:(实验结果)设置了文件存在的时候触发,创建了文件,触发了服务,然后删除了文件即破坏了触发条件,服务不会被停止。要做到此类需求,可以编写另外一个path单元,用于监控触发条件被破坏时,即监控一个反面的触发条件,当满足条件时这个path单元触发停止之前进行中的服务的动作。

本节参考链接

Timer

Systemd中的.timer单元的功能和cron类似,但是同cron相比有更多的特性,例如配置语法更直观友好(更丰富和直观的时间单位,以及友好的日历事件等)、更丰富的控制选项(系统启后候等待时间,systemd启动后等待时间,距离服务单元上次活动或未活动多少时间再次激活等等),持久化支持(存储服务单元最后一次触发记录),休眠唤醒,流逝时间精度设置等等。
.timer单元的格式上同其他配置单元相同,特殊点在于[Timer] Section,部分配置选项如下:
  • OnActiveSec=:timer自身被激活后过多少时间激活任务。
    • 例如:OnActiveSec=1min,表示当该timer被激活后1分钟激活任务。
  • OnBootSec=:系统启动之后过多少时间激活任务。
    • 例如:OnBootSec=5min,表示系统启动5分钟之后激活任务。
  • OnStartupSec=:systemd服务启动之后过多少时间激活任务。
    • 例如:OnStartupSec=10min,表示在systemd启动10分钟之后激活任务。
  • OnUnitActiveSec=:距离上次timer激活任务之后多久再次激活任务的时间间隔。
    • 例如:OnUnitActiveSec=30min,表示timer在最后一次激活任务之后的30分钟将再次激活任务。
  • OnUnitInactiveSec=:defines a timer relative to when the unit the timer is activating was last deactivated.//todo
  • OnCalendar=:日期的设置,通过过指定的格式设置在某个月的第几天激活任务,或者一个星期中的某个时间激活任务。
    • 例如:OnCalendar= *-*-1 0:0:0,表示每个月的第一天开始的时候激活任务;OnCalendar=Mon,Sun 2014-*-* 01,02:23:00,表示2014年中每个星期1和星期日的1点和2点的23分的时候激活任务。
  • AccuracySec=:Timer流逝的时间精度设置,默认为1分钟。若想更准确,可设置为1us。
    • 设置建议:make sure to set this value as high as possible and as low as necessary 。
  • Unit=:指定激活的单元名称。若未指定,将默认执行与timer同名的service单元。
  • Persistent=[true,fales]:设置是否保存服务单元上一次激活的时间。此设置项只在设置了OnCalendar之后有效。
    • This is useful to catch up on missed runs of the service when the machine was off.
更详细的时间单位与日期设置请参看:systemd.time

实例

/etc/systemd/system//usr/lib/systemd/system创建example.service文件。
/etc/systemd/system/example.service
[Unit]
Description= Reset

[Service]
ExecStart=/usr/bin/echo "reset~"
创建timer文件,每5小时激活一次example.service,屏幕打印提醒:
/etc/systemd/system/remind-reset.timer
[Uni]
Description= Remind of reset

[Timer]
OnUnitActiveSec=5h
Unit=example.service

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable remind-reset.timer #设置开机启动
$ sudo systemctl start remin-reset.tmer #启动timer
对于/etc/cron.{daily,hourly,monthly,weekly}等目录,在Timer中没有默认类似的目录,需要手动创建timer调用target,然后将服务进程放入target即可。
例 /etc/cron.d/daily的替代:
定义/etc/systemd/system/timer-daily.timer
[Unit]
Description=Daily Timer

[Timer]
OnbootSec=5min
OnUnitActiveSec=1d
Unit=timer-daly.target

[Install]
WantedBy=basic.target
添加需要的target:/etc/systemd/system/timer-daily.target
[Unit]
Description=Dail Timer Target
StopWhenUnneeded=yes
创建与target同名的wants文件夹,/etc/systemd/system/timer-daily.target.wants,
设置开机自动激活timer
$ sudo systemctl enbale timer-daily.timer
然后将需要每天执行的服务进程.service文件 ln -s/etc/systemd/system/timer-daily.target.wants文件夹中间即可。

本节参考链接

Sysctl

在系统启动阶段,systemd-sysctl.service会自动读取以下三个目录中的配置文件设置内核参数:
  • /etc/sysctl.d/*.conf
  • /run/sysctl.d/*.conf
  • /usr/lib/sysctl.d/*.conf

操作

使用sysctl命令设置内核参数和载入配置文件。 加载所有配置文件
sudo sysctl --system
加载特定配置文件
sudo sysctl -p filename.conf
临时性设置某项内核参数
sudo sysctl kernel.domainname=hell-world  .
或
echo "hello-world" > /proc/sys/kernel/domainname
更多详细用法参考sysctl用户手册。

优先级

上文三个文件夹的优先级从上到下依次降低,即若/etc/sysctl.d//run/sysctl.d/中文件存在同名的设置条目,前者的设置将覆盖后者的设置。/run/sysctl.d/usr/lib/sysctl.d
注:目前debian testing(systemd 204)系统依然存在/etc/sysctl.conf,但在systemd 207之后,systemd只会加载应用/etc/sysctl.d/*.conf/usr/lib/sysctl.d/*.conf中的内容。/etc/sysctl.conf将被弃用,需要用户手动移动已存在的sysctl.conf至/etc/sysctl.d/99-sysctl.conf
注:目前debian testing 存在的/etc/sysctl.conf优先级高于其他三个目录中的配置文件。

文件格式与命名

配置文件内,使用正斜杆/或点号.分隔内核参数,例如kernel.domainname=debian等同于kernel-domainname=debiandebian将写入/pro/sys/kernel/domainname文件。
注意:若一个配置条目中第一个使用分隔符是点号,条目中点号和正斜杆是等价互换的;若第一个使用的分隔符号是正斜杆,其余的点号与正斜杆将保持不变。
例:net.ipv4.conf.enp3s0/200.forwarding 和 net/ipv4/conf/enp3s0.200/forwarding都指向 /proc/sys/net/ipv4/conf/enp3s0.200/forwarding
各个文件夹下的配置文件将按照文件名的字典序进行排序,所以配置生效或者覆盖等情况将受此影响。建议将配置文件命名为 [2个数字]+-+[直观的名称]+.conf,通过设置名称开头的数字控制加载配置顺序。

本节参考链接

Unique Machinehandling ID

systemd新规定了一个配置文件/etc/machine-id保存着本地系统的唯一机器ID。机器ID是以一个换行符结束、十六进制编码、32个字符、全小写的字符串(格式和D-Bus machine ID相同)。
机器ID通常在系统初次安装时通过工具systemd-machine-id-setup随机生成(符合v4 UUIDs标准,无需担心重复率),在生成之后,用户更改软件配置或者计算机更换硬件,都不会改变此ID
注:在之后再次启动的时候,若/etc/machine-id为空,将重新生成(可能不会改变,后文解释);若/etc/machine-id被删除,将不会重新生成该文件与id。(debian testing 实验)。

systemd-machine-id-setup

systemd-machine-id-setup在系统安装时用于初始化机器ID,之后可以手动调用此工具用于生成机器ID,但是/etc/machine-id已存在并且不为空,将不会进行任何操作。
另外若在systemd-machine-id-setup 初始化/etc/machine-id之前,D-Bus machine ID(/var/lib/dbus/machine-id)已存在,将拷贝后者内容作为/etc/machine-id
注:/var/lib/dbus/machine-iddbus-uuidgen生成。
注:/etc/machine-id可能是/var/lib/dbus/machine-id的软链接文件。

本节参考链接

Dynamic host name and machine meta data handling

  • pretty hostname:级别最高,通常根据用户的桌面环境或shell呈现给用户,是一段可以包含所有特殊字符的UTF-8编码的字符串,对用户友好,例如“John‘s Laptop”,非常直观。若有可能 pretty hostname应该与/etc/hostname(下文介绍)相近,例如"John's Latop"对应的/etc/hostname可以是johns-laptop
  • static(configured) hostname:是一段不可以包含特殊符号或空格,全小写,7bit ASCII的字符串,一般是系统合法的域名。/etc/hostname用于存储static hostname,在引导时由内核使用,用户可手动指定。例如:"johns-laptop"。
  • transient(dynamic) hostname:transient hostname又名dynamic hostname,正如其名词,它是通过网络由DHCP服务器动态分配,临时的。格式上同 static hostname 相同。例如:“ dhcp-192-168-47-11”。
    • 注:若static hostname 已经设置且可用(非 localhost),transient hostname将被停用。
  • icon name:icon name被某些GUI程序用于可视化主机,命名上遵循XDG icon命名规范。
  • chassis type:一般依照计算机实际类型定义为:"desktop", "laptop", "server", "tablet", "handset",若是虚拟机将定义为:"vm"或"container"。

配置相关

可以通过hostname查看static hostname,或者进行临时性设置,static hostname存在/etc/hostname目录中。
$sudo hostname
debian
$sudo hostname debian-jessie #临时性更改hostname,关机丢失
debian-jessie
/etc/machine-info文件用于存储系统的pretty hostname,icon name以及chassis type。
注:debian tessting 在本文写成时默认不存在/etc/machine-info,需手动创建或通过hostnamectl工具(下文介绍)进行设置时将自动创建。
machine-info中包含以下三个条目:
  • PRETTY_HOSTNAME=
  • ICON_NAME=
  • CHASSIS=
PRETTY_HOSTNAME="Lennart's Tablet"
ICON_NAME=computer-tablet
CHASSIS=tablet
systemd内置了用于配置系统hostname的工具--hostnamectl。使用hostnamectl进行的配置是永久性的(transient hostname 除外),配置信息将写入/etc/hostname(static hostname)或/etc/machine-info(pretty hostname,icon name,classis type)。
显示系统元组信息
$ sudo hostnamectl
或
$ sudo hostnamectl status
返回示例
   Static hostname: johns-server
   Pretty hostname: john's server
Transient hostname: dhcp-123456
         Icon name: computer-vm
           Chassis: vm
        Machine ID: 0de206a66f9cf937239d126753c62e2f
           Boot ID: c30bb7e14e5a4381ae089b095c553047
    Virtualization: oracle
  Operating System: Debian GNU/Linux jessie/sid
            Kernel: Linux 3.14-1-486
      Architecture: i686
设置操作
$ sudo hostnamectl set-hostname [NAME]                #设置static hostname
$ sudo hostnamectl set-hostname --static [NAME]       #设置static hostname
$ sudo hostnamectl set-hostname --transient [NAME]    #设置transient hostname
$ sudo hostnamectl set-hostname --pretty   [NAME]     #设置pretty hostname,若包含特殊符号或者空格请加上空格
$ sudo hostnamectl set-icon-name [NAME]               #设置icon name
$ sudo hostnamectl set-chassis [TYPE]                 #设置chassis type
另外也可以直接编辑/etc/machine-info文件,修改pretty hostname,icon-name和chassis type,编辑时注意格式要求。编辑之后需要重启生效。

本节参考链接

Dependency based bootup

注:此部分内容与启动分析一节有重叠,但是考虑到本大节内容的完整性,未删去。
在SysV init中,通过给/etc/rcN.d目录下的启动目标设置不同的启动数字来控制启动依赖(先后顺序,串行执行,同步阻塞)。
上文已经介绍了systemd的target单元,systemd启动过程由target控制,不同的target之间有层级关系,也包含着不同的服务,相对于LSB的服务依赖控制方式更加简单和直观。
我们需要在系统到达某个target的时候启动某项服务,可以将服务对应的单元文件链接到target的wants文件夹下即可。
对于A依赖B,B依赖C,C依赖A的循环依赖关系,systemd会根据配置单元内依赖关系(required 强依赖;want 弱依赖)去掉若依赖来打破循环而修复问题,若无法修复则会报错。Systemd能够自动检测和修复这类配置错误,可保证有依赖相关的服务都可以正常启动(无法修复会报错)而不会出现互相依赖,以至于死锁的情况出现。
在单元文件内部,可以通过AfterBeforeConficts等等限制启动顺序与依赖性以及防止冲突等,具体在进程管理一节分析。
With systemd, dependencies can be resolved by designing the unit files correctly. The most typical case is that the unit A requires the unit B to be running before A is started. In that case add Requires=B and After=B to the [Unit] section of A. If the dependency is optional, add Wants=B and After=B instead. Note that Wants= and Requires= do not imply After=, meaning that if After= is not specified, the two units will be started in parallel.
得益于systemd的socket-based activation(以及解决了D-Bus依赖,文件系统依赖等),有依赖性的服务可以几乎同时启动,具体在socket-based activation一节分析。
P.S.关于启动请参看上文 启动分析一节。

系统时间管理

timedatectl

systemd提供了用于查询和设置系统时间和日期的工具--timedatectl。
注:下文中将提到的RTC即实时时钟,是计算机主板上的时钟设备(例:在BIOS中设备的时间)。操作系统会在启动阶段去读取RTC,然后设置系统时钟(又名内核时间)。而对系统时钟的更改也将会同步到RTC。
部分配置选项与实例
  • -H,--host=
    • 执行远程操作(over SSH)。注意其他操作参数需要写在-H之后,不然会提示错误信息:Too many arguments,远程执行完命令将自动返回本地控制终端。

  • status
    • 返回当前设置与状态,timedatectl不带命令参数默认与此等效。

    • 注:RTC可以设置为本地时间,也可以设置为世界时间。使用timedatectltimedatectl status将打印出三种时间,通过对比即可知道RTC是设置为本地时间还是世界时间。
  • set-time [TIME]
    • 设置系统时钟。同时也会更新硬件(RTC)时钟。TIME格式示例:“2011-11-11 11:11:11”,可省略某些设置项,例如只设置年月日:“2014-10-30”,只设置小时与分钟:“10:30”。
  • set-timezone [TIMEZOME]
    • 设置系统时区。可设置的时区可以用下文的list-timezones查看。若RTC是设置为本地时间,则更改时区之后RTC也会更新。
 #timedatectl set-timezone Asia/Shanghai
  • list-timezones
  • 列出可选的时区。set-timezone可设置为此选项打印出的时区。
#timedatectl list-timezones
  • set-local-rtc [BOOL]
  • 设置为“0”:RTC为世界时(UTC)
  • 设置为“1”:RTC为本地时
  • set-ntp [BOOL]
  • 选项:true,false。设置ntp同步时间是否打开(系统需安装ntp客户端且开启,如chrony客户端)。

timedated

systemd中一个用于控制系统时间和相关设置的daemon,它可以通过D-Bus进行访问,提供设置系统时间、时区、本地RTC、NTP服务器等接口。若想使用timedated接口进行相关工具脚本的编写请查看其官方文档,见本节参考链接。

timesyncd

systemd-timesyncd是systemd-213添加的一个新的daemon,用于同步系统时间。它内部实际上是实现了一个SNTP客户端,专注于同步时间,去掉了NTP那些繁多的功能。timesyncd以最小权限运行,且只有当网络可用时才进行工作。注意:若要使用timesyncd,确保在安装systemd时创建了为“systemd-timesync”的用户和用户组。
由于debian目前的systemd未提供此功能,以下配置文件来自systemd源代码目录。
若要启用timesyncd首先需要配置/etc/systemd/timesyncd.conf文件中的servers,多个NTPServer用空格隔开:
[Time]
Servers=0.asia.pool.ntp.org 1.asia.pool.ntp.org 2.asia.pool.ntp.org
设置开机自启动
# systemctl enable systemd-timesyncd

本节参考链接

系统临时文件管理

systemd-tmpfiles通过读取以下三个目录的配置文件来新建、清空、删除临时文件或目录。
  • /etc/tmpfiles.d/*.conf
  • /run/tmpfiles.d/*.conf
  • /usr/lib/tmpfiles.d/*.conf
在系统启动阶段,会按照以上目录下的配置文件新建、清空、删除临时文件或目录,同时也有timer单元文件自动清理超时文件。 系统管理员也可使用此工具用于管理临时文件。
# systemd-tmpfiles --[option] [config file path]
注:一条命令可同时指定多个选项。若未指定配置文件,将默认加载全部配置文件。
常见操作选项:
  • --create
  • 执行配置文件中创建文件或文件夹的行(with:f,F,w,d,D,p,L,c,b..)。
  • --clean
  • 所有超时的临时文件或目录将被删除(age)。
  • --remove
  • 执行配置文件中删除文件或文件夹的行(with:r,R..)。
  • --boot
  • 执行配置文件中带有的行(即在系统启动时才会执行的行)。

配置文件

配置文件目录:
  • /etc/tmpfiles.d/*.conf
  • /run/tmpfiles.d/*.conf
  • /usr/lib/tmpfiles.d/*.conf
以上目录优先级从上至下依次降低。若存在同名的配置文件,优先级高的目录中的配置文件将覆盖优先级低。若配置文件中存在配置错误的行,将会被自动忽略,不影响其他行的执行。管理员编写的配置文件应放在/etc/tmpfiles.d/目录下,程序安装时生成的配置文件应在/usr/lib/tmpfiles.d目录下。
以下为实验结论,官方文档暂未有此部分相关说明:
若对同一文件或目录有不同的操作(不保存新建后再删除此类操作,一般为新建同一文件或目录为不同类型的时出现),调用systemd-tmpfiles进行执行时,将提示存在冲突的临时文件或目录。若相同文件内有此类冲突行,排列在前的行将被执行,后续冲突的行不执行。若同一目录下不同文件内冲突行,将配置文件文件名按字典序排序,在前的文件中的行将被执行,之后的文件中的行被忽略。若不同目录中的不同名文件存在行冲突,优先级低的目录下的文件中的行将被执行(感觉奇怪。。不过是实验结果如此)。
tmpfiles配置文件一行即一条配置信息,包含五个部分:
Type,Path,Mode,UID,GUID,Age,Argument:
#例
#Type Path        Mode UID  GID  Age Argument
d    /run/user   0755 root root 10d -
L    /tmp/foobar -    -    -    -   /dev/null
  • Type:表示操作类型,是要新建(f,F,d,D..)还是删除(r,R..))文件或目录,还是要创建一个链接或一个设备块等,还是要调整临时文件的访问模式等。若某行只要在启动时执行,需在Type后加上,例如R!
  • Path:表示临时文件或目录的路径。Path支持部分通匹符与符号扩展(例如:%H表示Host name),具体请参考用户手册。
  • Mode:访问模式。若省略或设置为-,则目录默认为0755,文件默认为0644,若此时Type为z,则Mode不变。此参数在Type为x,r,R,L时忽略。
  • UID:用户ID。若省略、设置为-或Type为z的行中,默认为0(root)。此参数在Type为x,r,R,L时忽略。
  • GIO:用户组ID。其他同UID。
  • Age:临时文件或目录的存在时间,到期后将被自动删除。单位可为s,min,h,d,w,ms,m,us。若省略或设置为-,将不会自动清理。若以开头,例如~10d,指定目录下的内容会被保留,而更深级的目录与内容将全被删除(例:Path为/run/tmp1/,/run/tmp1/下的aa/,bb/,11文件与文件都会被保留,而例如aa/目录下cc/目录,22文件以及更深目录都将全被删除)。
    If the age field starts with a tilde character "~", the clean-up is only applied to files and directories one level inside the directory specified, but not the files and directories immediately inside it.
  • Argument:Type为c,b,f,F,w用于设置不同的参数,例如Type为L时用于设置链接的源文件,具体请参考用户手册。
关于以上选项的详细介绍请查看tmpfiles.d

实例

/usr/lib/tmpfiles.d/systemd.conf
d /run/user 0755 root root ~10d
F! /run/utmp 0664 root utmp -

f /var/log/wtmp 0664 root utmp -
f /var/log/btmp 0600 root utmp -

d /var/cache/man - - - 30d

d /run/systemd/ask-password 0755 root root -
d /run/systemd/seats 0755 root root -
d /run/systemd/sessions 0755 root root -
d /run/systemd/users 0755 root root -
d /run/systemd/machines 0755 root root -
d /run/systemd/shutdown 0755 root root -

m /var/log/journal 2755 root systemd-journal - -
Z /var/log/journal/%m 2755 root systemd-journal - -
m /run/log/journal 2755 root systemd-journal - -
Z /run/log/journal/%m 2755 root systemd-journal - -
/usr/lib/tmpfiles.d/debian.conf
# Type Path    Mode UID  GID  Age Argument
L /run/initctl -    -    -    -   /dev/initctl
d /run/sendsigs.omit.d 0755 root root -

本节参考链接

网络管理

注:systemd>=210才存在 systemd-networked 用于网络配置。
systemd-networked的配置文件存在于三个目录下,
  • /etc/systemd/network/
  • /run/systemd/network/
  • /usr/lib/systemd/network/
以上三个目录优先级从上到下依次降低。三个目录中的配置文件将被一起收集按照字典序排序,和它们在哪个目录中无关系,只有在处理同名文件时候才会考虑到目录优先级。若存在同名配置文件,优先级低的配置文件将被忽略。
有三种配置文件与systemd-networked相关,扩展名分别为'.link','.netdev','.network'。
  • .link:当网络设备就绪时,udev将匹配对应的.link文件
  • .netdev:对匹配的环境创建虚拟网络设备
  • .network:对匹配的设备进行网络配置
systemd-networked的配置文件格式上与systemd的单元文件格式相同,但是不再有后者那些常见的section,三种不同的配置文件各自有一些特有的seciton。对于配置文件的section与其中的众多选项意义不做繁杂的解释,请参考本节的参考链接。 将通过具体例子对三种配置进行大致介绍。

.link

wireless0.link
[Match]
MACAddress=12:34:56:78:9a:bc
Driver=brcmsmac
Path=pci-0000:02:00.0-*
Type=wlan
Virtualization=no
Host=my-laptop
Architecture=x86-64

[Link]
Name=wireless0
MTUBytes=1450
BitsPerSecond=10M
WakeOnLan=magic
MACAddress=cb:a9:87:65:43:21
[Mactch]section中指定了设备的mac地址,以及链接PCI总线使用的驱动brcmsmac,还有设备的工作环境(是否为虚拟环境,主机名称,系统架构等)。当对应mac地址的网络设备出现时,匹配后,[Link]section将请求udev将设备改名为wireless0,然后改变MTUbytes,设置BitPerSecond,打开WakeOnLan。同时也重新设置了设备的mac地址。另外还可以通过选项MACAddressPolicy将网络设备的mac地址设为随机,具体请参看networkd用户手册。

.netdev

Bridge
bridge0.netdev
[NetDev]
Name=bridge0
Kind=bridge
添加以上配置文件到对应目录,然后可在其他.network文件中设置网桥Bridge=bridge0。networkd启动之后,即会将.network文件匹配到的网络设备添加到对应网桥。
VLAN
vlan0.netdev
[NetDev]
Name=vlan1
Kind=vlan

[VLAN]
Id=1
vlan1.netdev
[NetDev]
Name=vlan2
Kind=vlan

[VLAN]
Id=2
将以上配置文件加入对于目录,即可在.network文件中设置VLAN VLAN=vlan1 vlan2。当networkd启动之后,对应.network文件中的设备就绪后即会自动创建VLAN。

.network

ethX.network
[Match]
Name=eth*

[Network]
DHCP=yes
将名称以eth(若eth0,eth1)开头的网络接口都开启DHCP服务配置。
enp2s0.network
[Match]
Name=enp2s0

[Network]
Address=192.168.0.15/24
Gateway=192.168.0.1
设置名称为enp2s0的网络接口的地址与网关。
若要对单网络接口设置多个IP,可以使用多个[Address]section,见:add multiple static ip addresses to a server with systemd-networkd
注:[Network]中可通过DNS=指定一个DNS服务器地址。
注:启用systemd-networked后,须关闭dhcpcd.service与所有netctl服务。
注:systemd-213新增加了 systemd-resolved ,用于管理系统DNS。systemd-resolved会将 /etc/resolv.conf链接到/run/systemd/resolve/resolv.conf/etc/resolv.conf文件的的相关设置以及格式没有变化,启用systemd-resolved之后设置依然通过修改/etc/resolv.conf文件。

本节参考链接

SysV兼容性

Systemd 提供了和 Sysvinit 以及 LSB initscripts 兼容的特性。 系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。
请尽量按照标准编写LSBInit Scripts,若不符合标准可能带来兼容性问题,具体兼容性问题需要进一步调研。 标准化启动脚本和改写为systemd service单元文件是更长远和低成本的选择。
注:Systemd 214 之后“The support for SysV and LSB init scripts has been reomved from the systemd daemon itself”,取而代之的,systemd将会有一个生成器根据这些脚本生成systemd原生的unit文件。对于此生成器如何处理依赖关系、runlevel暂时未知。
The support for SysV and LSB init scripts has been removedfrom the systemd daemon itself. Instead, it is nowimplemented as a generator that creates native systemd unitsfrom these scripts when needed. This enables us to remove asubstantial amount of legacy code from PID 1, following thefact that many distributions only ship a very small numberof LSB/SysV init scripts nowadays.

service与systemctl命令

systemd中除了提供systemctl(用户手册)用于控制管理服务,也提供了老式的service命令管理服务。 但是查看service脚本文件,即可发现若系统安装了systemd之后使用service命令的时候实际上是调用systemctl命令:
/usr/sbin/service(debian下路径与官方博客中的/sbin/service不同)
可知实际调用的是systemctl ${ACTION} ${UNIT} ,其实如果使用service status [NAME]也可发现返回的结果是systemd类型的服务进程状态。 所以servicesystemctl都可以对/etc/init.d/和systemd的.service进行操作管理。若存在同名的服务,systemd的.serviced单元优先级高于sysv脚本。

不兼容点(注意点)

Systemd仍然与SysV/LSB存在一些不兼容的地方和注意的点,罗列如下:
  • 各个发行版本对LSB/SysV初始化脚本进行的一些定制扩展,例如openSUSE对LSB头部内容进行了扩展,存在# X-Start-Before:# X-Stop-After:等专有的行。Systemd目前不支持此类扩展。
  • 不推荐使用/etc/init.d/xxx来管理旧的服务进程,建议使用service命令。
    • "invoking the init script directly has always been suboptimal since too much of the caller's execution context (environment block, umask, resource limits, audit trails, ...) ended up being inherited by the service, and invocation via "/sbin/service" used to clean this up at least partially. "
  • 若sysv脚本中LSB头部中依赖信息缺少或者不正确,systemd会全部解析并在运行时候尽量遵循解析的规则。为了保证服务正常运行,请在LSB头部清晰的、正确的定义依赖关系。
  • systemd下的启动脚本都有超时设置。
  • service单元执行的时候没有附带任何上下文环境,甚至没有进行$HOME目录的设置。对这些有依赖的启动脚本将无法正常工作。
  • service单元无法从stdin读取内容,默认连接到/dev/null。即不支持交互式启动脚本(i.e. Debian's X-Interactive in the LSB header)。
  • 不支持其他控制操作,只支持标准的start,stop,restart等等。
  • 标准的控制操作(i.e start,stop,restart..)不支持附加的参数。
  • systemd只停止正在运行的服务。
    • 对具体使用似乎没什么影响。
  • /sbin/chkconfig可能返回误导性的内容,所以请使用systemctl命令。
    • chkconfig常见使用命令用systemctl替代:
    • chkconfig servicename on : systemctl enable servicename.service
    • chkconfig servicename off :systemctl disable servicename.service
    • chkconfig --list :systemctl list-unit-files --type=service(preferred) 或者 ls /etc/systemd/system/*.wants/
    • chkconfig servicename --list: ls /etc/systemd/system/*.wants/servicename.service
    • chkconfig servicename --add :systemctl daemon-reload
  • Early boot runlevels as they are used by some distributions are no longer supported. i.e. "fake", distribution-specific runlevels such as "S" or "b" cannot be used with systemd.
  • System V services are not permitted to acquire realtime scheduling, even with root privileges.My Service Can't Get Realtime!

将SysV init脚本转化为Systemd Service单元文件(实例)

如果情况允许应该尽量将旧的sysv init脚本手动改写为systemd的service单元文件,不仅仅意味着不用担心兼容性问题,原生的service文件在使用上更能与systemd的其他单元文件配合,也同时能享受systemd带来的诸多特性与便利。
以下是一个将sysv init脚本转化为service文件的例子(来自systemd作者Blog):
/usr/sbin/abrtd( Automatic Bug Reporting Tool,Fedora发行版本中常见的默认工具)
#!/bin/bash
# Starts the abrt daemon
#
# chkconfig: 35 82 16
# description: Daemon to detect crashing apps
# processname: abrtd
### BEGIN INIT INFO
# Provides: abrt
# Required-Start: $syslog $local_fs
# Required-Stop: $syslog $local_fs
# Default-Stop: 0 1 2 6
# Default-Start: 3 5
# Short-Description: start and stop abrt daemon
# Description: Listen to and dispatch crash events
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions
ABRT_BIN="/usr/sbin/abrtd"
LOCK="/var/lock/subsys/abrtd"
OLD_LOCK="/var/lock/subsys/abrt"
RETVAL=0

#
# Set these variables if you are behind proxy
#
#export http_proxy=
#export https_proxy=

#
# See how we were called.
#

check() {
        # Check that we're a privileged user
        [ "`id -u`" = 0 ] || exit 4

        # Check if abrt is executable
        test -x $ABRT_BIN || exit 5
}

start() {

        check

        # Check if it is already running
        if [ ! -f $LOCK ] && [ ! -f $OLD_LOCK ]; then
                echo -n $"Starting abrt daemon: "
                daemon $ABRT_BIN
                RETVAL=$?
                [ $RETVAL -eq 0 ] && touch $LOCK
                echo
        fi
        return $RETVAL
}

stop() {

        check

        echo -n $"Stopping abrt daemon: "
        killproc $ABRT_BIN
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f $LOCK
        [ $RETVAL -eq 0 ] && rm -f $OLD_LOCK
        echo
        return $RETVAL
}


restart() {
        stop
        start
}

reload() {
        restart
}

case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
reload)
        reload
        ;;
force-reload)
        echo "$0: Unimplemented feature."
        RETVAL=3
        ;;
restart)
        restart
        ;;
condrestart)
        if [ -f $LOCK ]; then
                restart
        fi
        # update from older version
        if [ -f $OLD_LOCK ]; then
                restart
        fi
        ;;
status)
        status abrtd
        RETVAL=$?
        ;;
*)
        echo $"Usage: $0 {start|stop|status|restart| \
               condrestart|reload|force-reload}"
        RETVAL=2
esac

exit $RETVAL
转化为等价的service文件abrt.service
[Unit]
Description=Daemon to detect crashing apps
After=syslog.target

[Service]
ExecStart=/usr/sbin/abrtd
Type=forking

[Install]
WantedBy=multi-user.target
通过上面这个例子,我们能明显的感觉到sysv init脚本转化为service文件之后,变得非常短小(115行变为10行),也非常易懂。在service文件中, 大量的细节被隐藏,只需设置常见的脚本描述、依赖关系、执行路径等,另外在service文件中更多进行更多的设置,例如对服务进程资源的限制、工作路径的限制等等。
  • 关于service文件的编写规则将在专门的文档中描述。
  • 关于本例子转换的更多细节请单击下文作者blog的文章链接。

本节参考链接

container(systemd-nspawn)

systemd中可以在service文件中指定RootDirectory来进行chroot,具体请查看进程权限与安全管理一节, 但是systemd本身提供了比chroot更先进和方便的轻量级命名空间(Linux Namespace)容器管理工具:systemd-nspawn。 我们可以使用systemd-nspawn非常简单的在系统中创建简单的轻量级的容器,而且它比chroot更安全(对宿主OS的隔离更彻底), systemd-nspawn会自动在容器中挂载/proc,/sys节点,整体操作上更加简单。 Lennart的blog中列出了4点systemd-naspawn的优点如下[本节参考链接1]:
  • It's really easy to use. No need to manually mount /proc and /sys into your chroot() environment. The tool will do it for you and the kernel automatically cleans it up when the container terminates.
  • The isolation is much more complete, protecting the host OS from accidental changes from inside the container.
  • It's so good that you can actually boot a full OS in the container, not just a single lonesome shell.
  • It's actually tiny and installed everywhere where systemd is installed. No complicated installation or setup.
关于systemd-nspawn命令的使用和更多用例子请查看本节参考链接[3], 一个简单的实例(debian-stable-i386):
# debootstrap --arch=i386 stable ~/debian-tree/ 
# systemd-nspawn -D ~/debian-tree/
执行结果见图 systemd-nspawn-debian-stable。
systemd默认存在与systemd-nsapwn相关的service单元模板文件(关于模板文件请查看基础--进程管理--instandtiated service 一节),可用于配置开机启动容器。
/lib/systemd/system/systemd-nspawn@.service:
[Unit]
Description=Container %i
Documentation=man:systemd-nspawn(1)

[Service]
ExecStart=/usr/bin/systemd-nspawn -bjD /var/lib/container/%i
Type=notify

[Install]
WantedBy=multi-user.target
根据这个service文件,我们可知,只需要将容器目录移动到/var/lib/container/下或者创建链接到此目录(container默认不存在,需手动创建),然后使对应服务单元开启自启动即可。
以上文创建的debian-tree容器为例:
# mkdir -p /var/lib/container/
# ln -s ~/debian-tree /var/lib/container/debian-tree
# systemctl enable systemd-nspawn@debian-tree
注意:实验过程中遇到的一个已知的bug(kernel >= 3.14)
kernel auditing is broken when used with systemd's container code. When using systemd in conjunction with containers, please make sure to either turn off auditing at runtime using the kernel command line option "audit=0", or turn it off at kernel compile time using: CONFIG_AUDIT=n
另外可使用macinectl查看与管理系统中的容器,具体用法请查看本节参考链接[2,4],注意参考链接4为systemd-215的用户手册,不同版本的功能上可能有略微差异,具体请man machinectl

本节参考链接

  1. Changing Roots
  2. Arch systemd container
  3. systemd-nspawn
  4. machinectl

Systemd sysusers

注:sysusers 是systemd 215新加入的工具,用于添加系统用户和用户组(非普通用户)。
systemd-sysusers 使用 /usr/lib/sysusers.d/*.conf下的配置文件后直接访问/etc/passwd/etc/group文件创建系统用户和用户组在系统启动的时候或者软件包安装的时候(注:此工具不支持创建非系统用户和用户组)。

配置文件格式

# Type Name ID GECOS
u httpd 440 "HTTP User"
u authd /usr/bin/authd "Authorization user"
g input - -
m authd input
  • Type为操作类型
  • u:创建未存在的系统用户。用户的主用户组将是与其同名的用户组。shell是/sbin/login,home目录为/。此类用户不允许登录。
  • g:创建未存在的系统用户组。无密码设置。
  • m:添加一个系统用户至一个用户组。若用户或者用户组不存在,将自动创建。
  • Name为用户名
  • ID为用户ID,若未指定(-),将自动生成。
  • GECOS为所创建的系统用户简短的描述说明
注:若用户或用户组已存在,systemd-sysusers不会做任何操作,不会覆盖已存在的用户或用户组。

优势

systemd在 sysusers.d/下有两个配置文件,包含最小系统所需要的基础系统用户和用户组,systemd-sysusers将在early boot 创建这些系统用户和用户组,这个特性对于启动时候/etc目录为空的系统非常有用(factory resets and volatile systems)。

本节参考链接

Snapshotting of systemd state

Systemd的快照功能不是操作系统的快照,而是systemd本身运行状态(systemd中各单元与服务的状态)的快照。systemd中的.snapshot 单元与其.target单元类似,都只是引用其他的单元。 由于Systemd支持按需启动(例如一个socket配置单元对应一个service单元,当有连接进入socket时候,启动对应服务),导致系统运行状态多变,使用快照我们可以保存systemd中各单元的状态,以及回滚恢复到某个状态。比如系统当前正运行服务A和B,可以对当前系统运行状况创建快照,然后将进程A停止,或者做其他的任意的对系统的改变,比如启动新的进程C。在这些改变之后,运行快照恢复命令,就可立即将系统恢复到快照时刻的状态,即只有服务A,B在运行。
一个可能的应用场景是调试:比如服务器出现一些异常,为了调试可将当前状态保存为快照,然后可以进行任意的操作,比如停止服务等等。等调试结束,恢复快照即可。

具体操作

与其他配置单元不同,快照单元不是通过磁盘上的配置文件进行管理,而是通过systemctl snapshot命令进行动态生成和管理,保存在内存中。
生成快照:
$ sudo systemctl snapshot fpm1
fpm1.snapshot

$ sudo systemctl snapshot #未指定快照名称时,将默认生成 snapshot-N.snaphshot
snapshot-1.snapshot

$ sudo systemctl snapshot
snapshot-2.snashot
查看所有快照,及其状态:
$sudo systemctl -all list-units|grep snapshot
fpm1.snapshot              loaded inactive dead      fpm1.snapshot
snapshot-1.snapshot        loaded inactive dead      snapshot-1.snapshot
snapshot-2.snapshot        loaded inactive dead      snapshot-2.snapshot
查看某个快照内容:
$ sudo systemctl show fpm1

Id=fpm1.service
Names=fpm1.service
Description=fpm1.service
LoadState=error
ActiveState=inactive
SubState=dead
InactiveExitTimestampMonotonic=0
ActiveEnterTimestampMonotonic=0
ActiveExitTimestampMonotonic=0
InactiveEnterTimestampMonotonic=0
CanStart=yes
CanStop=yes
CanReload=no
CanIsolate=no
StopWhenUnneeded=no
RefuseManualStart=no
RefuseManualStop=no
AllowIsolate=no
DefaultDependencies=yes
OnFailureIsolate=no
IgnoreOnIsolate=no
IgnoreOnSnapshot=no
NeedDaemonReload=no
JobTimeoutUSec=0
ConditionTimestampMonotonic=0
ConditionResult=no
LoadError=org.freedesktop.DBus.Error.FileNotFound "No such file or directory"
Restart=no
NotifyAccess=none
RestartUSec=100ms
TimeoutUSec=1min 30s
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
WatchdogUSec=0
WatchdogTimestampMonotonic=0
StartLimitInterval=10000000
StartLimitBurst=5

....
删除快照:
$ sudo systemctl delete fpm1
还原快照:
$sudo systemctl isolate snapshot-1.snapshot
注:快照是保存在内存中,关机后即丢失,即不可以本次系统运行时保存快照,重启之后再恢复到该快照。
注:快照功能在systemd中并不完善,似乎开发人员也没有特别关注它,因此有报告指出它存在一些使用上的问题,使用需谨慎。

本节参考链接

-------------------------------

Systemd的简介和特点


Systemd是Linux系统中最新的初始化系统(init),它主要的设计目标是克服sysvinit固有的缺点,提高系统的启动速度。systemd和ubuntu的upstart是竞争对手,预计会取代UpStart,实际上在作者写作本文时(2014-07-16),已经有消息称Ubuntu也将采用systemd作为其标准的系统初始化系统。
Systemd的很多概念来源于苹果MacOS操作系统上的launchd,不过launchd专用于苹果系统,因此长期未能获得应有的广泛关注。Systemd借鉴了很多launchd的思想,它的重要特性如下:

同SysVinit和LSB initscripts兼容

Systemd是一个“新来的”,Linux上的很多应用程序并没有来得及为它做相应的改变。和UpStart一样,systemd引入了新的配置方式,对应用程序的开发也有一些新的要求。如果systemd想替代目前正在运行的初始化系统,就必须和现有程序兼容。任何一个Linux发行版都很难为了采用systemd而在短时间内将所有的服务代码都修改一遍。
Systemd提供了和Sysvinit以及LSB initscripts兼容的特性。系统中已经存在的服务和进程无需修改。这降低了系统向systemd迁移的成本,使得systemd替换现有初始化系统成为可能。

更快的启动速度

Systemd提供了比UpStart更激进的并行启动能力,采用了socket/D-Bus activation等技术启动服务。一个显而易见的结果就是:更快的启动速度。
为了减少系统启动时间,systemd的目标是:
  • 尽可能启动更少的进程
  • 尽可能将更多进程并行启动
同样地,UpStart也试图实现这两个目标。UpStart采用事件驱动机制,服务可以暂不启动,当需要的时候才通过事件触发其启动,这符合第一个设计目标;此外,不相干的服务可以并行启动,这也实现了第二个目标。
systemd比UpStart更进一步提高了并行启动能力,极大地加速了系统启动时间。

Systemd提供按需启动能力

当sysvinit系统初始化的时候,它会将所有可能用到的后台服务进程全部启动运行。并且系统必须等待所有的服务都启动就绪之后,才允许用户登录。这种做法有两个缺点:首先是启动时间过长;其次是系统资源浪费。
某些服务很可能在很长一段时间内,甚至整个服务器运行期间都没有被使用过。比如CUPS,打印服务在多数服务器上很少被真正使用到。您可能没有想到,在很多服务器上SSHD也是很少被真正访问到的。花费在启动这些服务上的时间是不必要的;同样,花费在这些服务上的系统资源也是一种浪费。
Systemd可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd可以关闭它,等待下次需要时再次启动它。

采用Linux的Cgroup特性跟踪和管理进程的生命周期

init系统的一个重要职责就是负责跟踪和管理服务进程的生命周期。它不仅可以启动一个服务,也必须也能够停止服务。这看上去没有什么特别的,然而在真正用代码实现的时候,您或许会发现停止服务比一开始想的要困难。
服务进程一般都会作为精灵进程(daemon)在后台运行,为此服务程序有时候会派生(fork)两次。在UpStart中,需要在配置文件中正确地配置expect小节。这样UpStart通过对fork系统调用进行计数,从而获知真正的精灵进程的PID号。

启动挂载点和自动挂载的管理

传统的Linux系统中,用户可以用/etc/fstab文件来维护固定的文件系统挂载点。这些挂载点在系统启动过程中被自动挂载,一旦启动过程结束,这些挂载点就会确保存在。这些挂载点都是对系统运行至关重要的文件系统,比如HOME目录。和sysvinit一样,Systemd管理这些挂载点,以便能够在系统启动时自动挂载它们。Systemd还兼容/etc/fstab文件,您可以继续使用该文件管理挂载点。
有时候用户还需要动态挂载点,比如打算访问DVD内容时,才临时执行挂载以便访问其中的内容,而不访问光盘时该挂载点被取消(umount),以便节约资源。传统地,人们依赖autofs服务来实现这种功能。
Systemd内建了自动挂载服务,无需另外安装autofs服务,可以直接使用systemd提供的自动挂载管理能力来实现autofs的功能。

实现事务性依赖关系管理

系统启动过程是由很多的独立工作共同组成的,这些工作之间可能存在依赖关系,比如挂载一个NFS文件系统必须依赖网络能够正常工作。Systemd虽然能够最大限度地并发执行很多有依赖关系的工作,但是类似”挂载NFS”和”启动网络”这样的工作还是存在天生的先后依赖关系,无法并发执行。对于这些任务,systemd维护一个”事务一致性”的概念,保证所有相关的服务都可以正常启动而不会出现互相依赖,以至于死锁的情况。

能够对系统进行快照和恢复

Systemd支持按需启动,因此系统的运行状态是动态变化的,人们无法准确地知道系统当前运行了哪些服务。Systemd快照提供了一种将当前系统运行状态保存并恢复的能力。
比如系统当前正运行服务A和B,可以用systemd命令行对当前系统运行状况创建快照。然后将进程A停止,或者做其他的任意的对系统的改变,比如启动新的进程C。在这些改变之后,运行systemd的快照恢复命令,就可立即将系统恢复到快照时刻的状态,即只有服务A,B在运行。一个可能的应用场景是调试:比如服务器出现一些异常,为了调试用户将当前状态保存为快照,然后可以进行任意的操作,比如停止服务等等。等调试结束,恢复快照即可。
这个快照功能目前在systemd中并不完善,似乎开发人员也没有特别关注它,因此有报告指出它还存在一些使用上的问题,使用时尚需慎重。

日志服务

systemd自带日志服务journald,该日志服务的设计初衷是克服现有的syslog服务的缺点。比如:
syslog不安全,消息的内容无法验证。每一个本地进程都可以声称自己是Apache PID 4711,而syslog也就相信并保存到磁盘上。
数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。Systemd Journal用二进制格式保存所有日志信息,用户使用journalctl命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。
Systemd Journal的优点如下:
  • 简单性:代码少,依赖少,抽象开销最小。
  • 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
  • 移植性:日志文件应该在所有类型的Linux系统上可用,无论它使用的何种CPU或者字节序。
  • 性能:添加和浏览日志非常快。
  • 最小资源占用:日志数据文件需要较小。
  • 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。Syslog将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
  • 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
  • 安全性:日志文件是可以验证的,让无法检测的修改不再可能。

Systemd的基本概念

单元的概念

系统初始化需要做的事情非常多。需要启动后台服务,比如启动sshd服务;需要做配置工作,比如挂载文件系统。这个过程中的每一步都被systemd抽象为一个配置单元,即unit。可以认为一个服务是一个配置单元;一个挂载点是一个配置单元;一个交换分区的配置是一个配置单元;等等。Systemd将配置单元归纳为以下一些不同的类型。然而,systemd正在快速发展,新功能不断增加。所以配置单元类型可能在不久的将来继续增加。
  • service:代表一个后台服务进程,比如mysqld。这是最常用的一类。
  • socket:此类配置单元封装系统和互联网中的一个套接字。当下,systemd支持流式、数据报和连续包的AF_INET、AF_INET6、AF_UNIX socket。每一个套接字配置单元都有一个相应的服务配置单元。相应的服务在第一个“连接”进入套接字时就会启动(例如:nscd.socket在有新连接后便启动nscd.service)。
  • device:此类配置单元封装一个存在于Linux设备树中的设备。每一个使用udev规则标记的设备都将会在systemd中作为一个设备配置单元出现。
  • mount:此类配置单元封装文件系统结构层次中的一个挂载点。Systemd将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd会将/etc/fstab中的条目都转换为挂载点,并在开机时处理。
  • automount:此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元,当该自动挂载点被访问时,systemd执行挂载点中定义的挂载行为。
  • swap:和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
  • target:此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。(例如:multi-user.target相当于在传统使用SysV的系统中运行级别5)
  • timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了atd、crond等传统的定时服务。
  • snapshot:与target配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
每个配置单元都有一个对应的配置文件,系统管理员的任务就是编写和维护这些不同的配置文件,比如一个MySQL服务对应一个mysql.service文件。这种配置文件的语法非常简单,用户不需要再编写和维护复杂的系统5脚本了。

依赖关系

虽然systemd将大量的启动工作解除了依赖,使得它们可以并发启动。但还是存在有些任务,它们之间存在天生的依赖,不能用“套接字激活”(socket activation)、D-Bus activation和autofs三大方法来解除依赖(三大方法详情见后续描述)。比如:挂载必须等待挂载点在文件系统中被创建;挂载也必须等待相应的物理设备就绪。为了解决这类依赖问题,systemd的配置单元之间可以彼此定义依赖关系。
Systemd用配置单元定义文件中的关键字来描述配置单元之间的依赖关系。比如:unit A依赖unit B,可以在unit B的定义中用”require A”来表示。这样systemd就会保证先启动A再启动B。

Systemd事务

Systemd能保证事务完整性。Systemd的事务概念和数据库中的有所不同,主要是为了保证多个依赖的配置单元之间没有环形引用。

Target和运行级别

Systemd用目标(target)替代了运行级别的概念,提供了更大的灵活性,如您可以继承一个已有的目标,并添加其它服务,来创建自己的目标。下表列举了systemd下的目标和常见runlevel的对应关系:
表1.Sysvinit运行级别和systemd目标的对应表
Sysvinit运行级别Systemd目标备注
0runlevel0.target, poweroff.target关闭系统。
1, s, singlerunlevel1.target, rescue.target单用户模式。
2, 4runlevel2.target, runlevel4.target, multi-user.target用户定义/域特定运行级别。默认等同于3。
3runlevel3.target, multi-user.target多用户,非图形化。用户可以通过多个控制台或网络登录。
5runlevel5.target, graphical.target多用户,图形化。通常为所有运行级别3的服务外加图形化登录。
6runlevel6.target, reboot.target重启
emergencyemergency.target紧急 Shell

Systemd 的并发启动原理

如前所述,在Systemd中,所有的服务都并发启动,比如Avahi、D-Bus、livirtd、X11、HAL可以同时启动。乍一看,这似乎有点儿问题,比如Avahi需要syslog的服务,Avahi和syslog同时启动,假设Avahi的启动比较快,所以syslog还没有准备好,可是Avahi又需要记录日志,这岂不是会出现问题?
Systemd的开发人员仔细研究了服务之间相互依赖的本质问题,发现所谓依赖可以分为三个具体的类型,而每一个类型实际上都可以通过相应的技术解除依赖关系。
并发启动原理之一:解决socket依赖
绝大多数的服务依赖是套接字依赖。比如服务A通过一个套接字端口S1提供自己的服务,其他的服务如果需要服务A,则需要连接S1。因此如果服务A尚未启动,S1就不存在,其他的服务就会得到启动错误。所以传统地,人们需要先启动服务A,等待它进入就绪状态,再启动其他需要它的服务。Systemd认为,只要我们预先把S1建立好,那么其他所有的服务就可以同时启动而无需等待服务A来创建S1了。如果服务A尚未启动,那么其他进程向S1发送的服务请求实际上会被Linux操作系统缓存,其他进程会在这个请求的地方等待。一旦服务A启动就绪,就可以立即处理缓存的请求,一切都开始正常运行。
那么服务如何使用由init进程创建的套接字呢?
Linux操作系统有一个特性,当进程调用fork或者exec创建子进程之后,所有在父进程中被打开的文件句柄(file descriptor)都被子进程所继承。套接字也是一种文件句柄,进程A可以创建一个套接字,此后当进程A调用exec启动一个新的子进程时,只要确保该套接字的close_on_exec标志位被清空,那么新的子进程就可以继承这个套接字。子进程看到的套接字和父进程创建的套接字是同一个系统套接字,就仿佛这个套接字是子进程自己创建的一样,没有任何区别。
这个特性以前被一个叫做inetd的系统服务所利用。Inetd进程会负责监控一些常用套接字端口,比如Telnet,当该端口有连接请求时,inetd才启动telnetd进程,并把有连接的套接字传递给新的telnetd进程进行处理。这样,当系统没有telnet客户端连接时,就不需要启动telnetd进程。Inetd可以代理很多的网络服务,这样就可以节约很多的系统负载和内存资源,只有当有真正的连接请求时才启动相应服务,并把套接字传递给相应的服务进程。
和inetd类似,systemd是所有其他进程的父进程,它可以先建立所有需要的套接字,然后在调用exec的时候将该套接字传递给新的服务进程,而新进程直接使用该套接字进行服务即可。
并发启动原理之二:解决D-Bus依赖
D-Bus是desktop-bus的简称,是一个低延迟、低开销、高可用性的进程间通信机制。它越来越多地用于应用程序之间通信,也用于应用程序和操作系统内核之间的通信。很多现代的服务进程都使用D-Bus取代套接字作为进程间通信机制,对外提供服务。比如简化Linux网络配置的NetworkManager服务就使用D-Bus和其他的应用程序或者服务进行交互:邮件客户端软件evolution可以通过D-Bus从NetworkManager服务获取网络状态的改变,以便做出相应的处理。
D-Bus支持所谓”bus activation”功能。如果服务A需要使用服务B的D-Bus服务,而服务B并没有运行,则D-Bus可以在服务A请求服务B的D-Bus时自动启动服务B。而服务A发出的请求会被D-Bus缓存,服务A会等待服务B启动就绪。利用这个特性,依赖D-Bus的服务就可以实现并行启动。
并发启动原理之三:解决文件系统依赖
系统启动过程中,文件系统相关的活动是最耗时的,比如挂载文件系统,对文件系统进行磁盘检查(fsck),磁盘配额检查等都是非常耗时的操作。在等待这些工作完成的同时,系统处于空闲状态。那些想使用文件系统的服务似乎必须等待文件系统初始化完成才可以启动。但是systemd发现这种依赖也是可以避免的。
Systemd参考了autofs的设计思路,使得依赖文件系统的服务和文件系统本身初始化两者可以并发工作。autofs可以监测到某个文件系统挂载点真正被访问到的时候才触发挂载操作,这是通过内核automounter模块的支持而实现的。比如一个open()系统调用作用在”/misc/cd/file1″的时候,/misc/cd尚未执行挂载操作,此时open()调用被挂起等待,Linux内核通知autofs,autofs执行挂载。这时候,控制权返回给open()系统调用,并正常打开文件。
Systemd集成了autofs的实现,对于系统中的挂载点,比如/home,当系统启动的时候,systemd为其创建一个临时的自动挂载点。在这个时刻/home真正的挂载设备尚未启动好,真正的挂载操作还没有执行,文件系统检测也还没有完成。可是那些依赖该目录的进程已经可以并发启动,他们的open()操作被内建在systemd中的autofs捕获,将该open()调用挂起(可中断睡眠状态)。然后等待真正的挂载操作完成,文件系统检测也完成后,systemd将该自动挂载点替换为真正的挂载点,并让open()调用返回。由此,实现了那些依赖于文件系统的服务和文件系统本身同时并发启动。
当然对于/根目录的依赖实际上一定还是要串行执行,因为systemd自己也存放在/之下,必须等待系统根目录挂载检查好。
不过对于类似/home等挂载点,这种并发可以提高系统的启动速度,尤其是当/home是远程的NFS节点,或者是加密盘等,需要耗费较长的时间才可以准备就绪的情况下,因为并发启动,这段时间内,系统并不是完全无事可做,而是可以利用这段空余时间做更多的启动进程的事情,总的来说就缩短了系统启动时间。

Systemd 的使用

下面针对技术人员的不同角色来简单地介绍一下systemd的使用。本文只打算给出简单的描述,让您对systemd的使用有一个大概的理解。具体的细节内容太多,即无法在一篇短文内写全,本人也没有那么强大的能力。还需要读者自己去进一步查阅systemd的文档。

系统软件开发人员

开发人员需要了解systemd的更多细节。比如您打算开发一个新的系统服务,就必须了解如何让这个服务能够被systemd管理。这需要您注意以下这些要点:
  • 后台服务进程代码不需要执行两次派生来实现后台精灵进程,只需要实现服务本身的主循环即可。
  • 不要调用setsid(),交给systemd处理
  • 不再需要维护pid文件。
  • Systemd提供了日志功能,服务进程只需要输出到stderr即可,无需使用syslog。
  • 处理信号SIGTERM,这个信号的唯一正确作用就是停止当前服务,不要做其他的事情。
  • SIGHUP信号的作用是重启服务。
  • 需要套接字的服务,不要自己创建套接字,让systemd传入套接字。
  • 使用sd_notify()函数通知systemd服务自己的状态改变。一般地,当服务初始化结束,进入服务就绪状态时,可以调用它。
Unit文件的编写
对于开发者来说,工作量最大的部分应该是编写配置单元文件,定义所需要的单元。
举例来说,开发人员开发了一个新的服务程序,比如httpd,就需要为其编写一个配置单元文件以便该服务可以被systemd管理,类似UpStart的工作配置文件。在该文件中定义服务启动的命令行语法,以及和其他服务的依赖关系等。
此外我们之前已经了解到,systemd的功能繁多,不仅用来管理服务,还可以管理挂载点,定义定时任务等。这些工作都是由编辑相应的配置单元文件完成的。我在这里给出几个配置单元文件的例子。
下面是SSH服务的配置单元文件,服务配置单元文件以.service为文件名后缀。
#cat /etc/system/system/sshd.service
[Unit]
Description=OpenSSH server daemon
[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usrsbin/sshd –D $OPTIONS
ExecReload=/bin/kill –HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
文件分为三个小节。第一个是[Unit]部分,这里仅仅有一个描述信息。第二部分是Service定义,其中,ExecStartPre定义启动服务之前应该运行的命令;ExecStart定义启动服务的具体命令行语法。第三部分是[Install],WangtedBy表明这个服务是在多用户模式下所需要的。
那我们就来看下multi-user.target吧:
#cat multi-user.target
[Unit]
Description=Multi-User System
Documentation=man.systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescure.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
[Install]
Alias=default.target
第一部分中的Requires定义表明multi-user.target启动的时候basic.target也必须被启动;另外basic.target停止的时候,multi-user.target也必须停止。如果您接着查看basic.target文件,会发现它又指定了sysinit.target等其他的单元必须随之启动。同样sysinit.target也会包含其他的单元。采用这样的层层链接的结构,最终所有需要支持多用户模式的组件服务都会被初始化启动好。
在[Install]小节中有Alias定义,即定义本单元的别名,这样在运行systemctl的时候就可以使用这个别名来引用本单元。这里的别名是default.target,比multi-user.target要简单一些。。。
此外在/etc/systemd/system目录下还可以看到诸如*.wants的目录,放在该目录下的配置单元文件等同于在[Unit]小节中的wants关键字,即本单元启动时,还需要启动这些单元。比如您可以简单地把您自己写的foo.service文件放入multi-user.target.wants目录下,这样每次都会被默认启动了。
最后,让我们来看看sys-kernel-debug.mout文件,这个文件定义了一个文件挂载点:
#cat sys-kernel-debug.mount
[Unit]
Description=Debug File Syste
DefaultDependencies=no
ConditionPathExists=/sys/kernel/debug
Before=sysinit.target
[Mount]
What=debugfs
Where=/sys/kernel/debug
Type=debugfs
Bash
这个配置单元文件定义了一个挂载点。挂载配置单元文件有一个[Mount]配置小节,里面配置了What,Where和Type三个数据项。这都是挂载命令所必须的,例子中的配置等同于下面这个挂载命令:
mount –t debugfs /sys/kernel/debug debugfs
Bash
配置单元文件的编写需要很多的学习,必须参考systemd附带的man等文档进行深入学习。希望通过上面几个小例子,大家已经了解配置单元文件的作用和一般写法了。

系统管理员

Systemd的主要命令行工具是systemctl。多数管理员应该都已经非常熟悉系统服务和init系统的管理,比如service、chkconfig以及telinit命令的使用。Systemd也完成同样的管理任务,只是命令工具systemctl的语法有所不同而已,因此用表格来对比systemctl和传统的系统管理命令会非常清晰。
表2.Systemd命令和sysvinit命令的对照表
Sysvinit 命令Systemd命令备注
service foo startsystemctl start foo.service用来启动一个服务 (并不会重启现有的)
service foo stopsystemctl stop foo.service用来停止一个服务 (并不会重启现有的)。
service foo restartsystemctl restart foo.service用来停止并启动一个服务。
service foo reloadsystemctl reload foo.service当支持时,重新装载配置文件而不中断等待操作。
service foo condrestartsystemctl condrestart foo.service如果服务正在运行那么重启它。
service foo statussystemctl status foo.service汇报服务是否正在运行。
ls /etc/rc.d/init.d/systemctl list-unit-files --type=service用来列出可以启动或停止的服务列表。
chkconfig foo onsystemctl enable foo.service在下次启动时或满足其他触发条件时设置服务为启用
chkconfig foo offsystemctl disable foo.service在下次启动时或满足其他触发条件时设置服务为禁用
chkconfig foosystemctl is-enabled foo.service用来检查一个服务在当前环境下被配置为启用还是禁用。
chkconfig --listsystemctl list-unit-files --type=service输出在各个运行级别下服务的启用和禁用情况
chkconfig foo --listls /etc/systemd/system/*.wants/foo.service用来列出该服务在哪些运行级别下启用和禁用。
chkconfig foo --addsystemctl daemon-reload当您创建新服务文件或者变更设置时使用。
telinit 3systemctl isolate multi-user.target (OR systemctl isolate runlevel3.target OR telinit 3)改变至多用户运行级别。
除了表2列出的常见用法,系统管理员还需要了解其他一些系统配置和管理任务的改变。
首先我们了解systemd如何处理电源管理,命令如下表所示:
表3.systemd电源管理命令
命令操作
systemctl reboot重启机器
systemctl poweroff关机
systemctl suspend待机
systemctl hibernate休眠
systemctl hybrid-sleep混合休眠模式(同时休眠到硬盘并待机)
关机不是每个登录用户在任何情况下都可以执行的,一般只有管理员才可以关机。正常情况下系统不应该允许SSH远程登录的用户执行关机命令。否则其他用户正在工作,一个用户把系统关了就不好了。为了解决这个问题,传统的Linux系统使用ConsoleKit跟踪用户登录情况,并决定是否赋予其关机的权限。现在ConsoleKit已经被systemd的logind所替代。
logind不是pid-1的init进程。它的作用和UpStart的sessioninit类似,但功能要丰富很多,它能够管理几乎所有用户会话(session)相关的事情。logind不仅是ConsoleKit的替代,它可以:
  • 维护,跟踪会话和用户登录情况。如上所述,为了决定关机命令是否可行,系统需要了解当前用户登录情况,如果用户从SSH登录,不允许其执行关机命令;如果普通用户从本地登录,且该用户是系统中的唯一会话,则允许其执行关机命令;这些判断都需要logind维护所有的用户会话和登录情况。
  • Logind也负责统计用户会话是否长时间没有操作,可以执行休眠/关机等相应操作。
  • 为用户会话的所有进程创建CGroup。这不仅方便统计所有用户会话的相关进程,也可以实现会话级别的系统资源控制。
  • 负责电源管理的组合键处理,比如用户按下电源键,将系统切换至睡眠状态。
  • 多席位(multi-seat)管理。如今的电脑,即便一台笔记本电脑,也完全可以提供多人同时使用的计算能力。多席位就是一台电脑主机管理多个外设,比如两个屏幕和两个鼠标/键盘。席位一使用屏幕1和键盘1;席位二使用屏幕2和键盘2,但他们都共享一台主机。用户会话可以自由在多个席位之间切换。或者当插入新的键盘,屏幕等物理外设时,自动启动gdm用户登录界面等。所有这些都是多席位管理的内容。ConsoleKit始终没有实现这个功能,systemd的logind能够支持多席位。
以上描述的这些管理功能仅仅是systemd的部分功能,除此之外,systemd还负责系统其他的管理配置,比如配置网络,Locale管理,管理系统内核模块加载等,完整地描述它们已经超出了本人的能力。

systemd 小结

在不才作者看来,作为系统初始化系统,systemd的最大特点有两个:
  • 令人惊奇的激进的并发启动能力,极大地提高了系统启动速度;
  • 用CGroup统计跟踪子进程,干净可靠。
此外,和其前任不同的地方在于,systemd已经不仅仅是一个初始化系统了。
Systemd出色地替代了sysvinit的所有功能,但它并未就此自满。因为init进程是系统所有进程的父进程这样的特殊性,systemd非常适合提供曾经由其他服务提供的功能,比如定时任务(以前由crond完成);会话管理(以前由ConsoleKit/PolKit等管理)。仅仅从本文皮毛一样的介绍来看,Systemd已经管得很多了,可它还在不断发展。它将逐渐成为一个多功能的系统环境,能够处理非常多的系统管理任务,有人甚至将它看作一个操作系统。
好的一点是,这非常有助于标准化Linux的管理!从前,不同的Linux发行版各行其事,使用不同方法管理系统,从来也不会互相妥协。比如如何将系统进入休眠状态,不同的系统有不同的解决方案,即便是同一个Linux系统,也存在不同的方法,比如一个有趣的讨论:如何让ubuntu系统休眠,可以使用底层的/sys/power/state接口,也可以使用诸如pm-utility等高层接口。存在这么多种不同的方法做一件事情对像我这样的普通用户而言可不是件有趣的事情。systemd提供统一的电源管理命令接口,这件事情的意义就类似全世界的人都说统一的语言,我们再也不需要学习外语了,多么美好!
如果所有的Linux发行版都采纳了systemd,那么系统管理任务便可以很大程度上实现标准化。此外systemd有个很棒的承诺:接口保持稳定,不会再轻易改动。对于软件开发人员来说,这是多么体贴又让人感动的承诺啊!

结束语

本系列文章从古老却简明稳定的sysvinit说起,接着简要描述了UpStart带来的清新改变,最后看到了充满野心和活力的新生代systemd系统逐渐统治Linux的各个版本。就好像在看我们这个世界,一代人老去,新的一代带着横扫一切的气概登上舞台,还没有喊出他们最有力的口号,更猛的一代已经把聚光灯和所有的目光带走。Systemd之后也许还有更新的init系统出现吧,让我们继续期待。。。