systemd (简体中文)

From ArchWiki
Revision as of 07:03, 1 January 2013 by Cuihao (Talk | contribs) (疑难解答)

Jump to: navigation, search

Template:Article summary start Template:Article summary text Template:Article summary heading Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary end

翻译状态: 本文是英文页面 Systemd翻译,最后翻译时间:2012-11-29,点击这里可以查看翻译后英文页面的改动。

摘自项目主页:

systemd 是 Linux 下的一款系统和服务管理器,兼容 SysV 和 LSB 的启动脚本。systemd 的特性有:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点;各服务间基于依赖关系进行精密控制。systemd 完全可以替代 Arch 默认的sysvinit启动系统。

注意: 这个帖子详细解释了 Arch 向 systemd 迁移的原因。

另见维基百科上的介绍

迁移前需考虑

  • 阅读该站,了解 systemd。
  • systemd 自己有一套日志(journal)系统,用于代替 syslog。两者也可以共存,参见后面的日志部分
  • 虽然 systemd 可以替换 cronacpidxinetd 等的部分功能。至少目前还可以继续使用这些服务,无需立即切换。
  • 交互式 initscripts 启动脚本在 systemd 中无法工作。例如 netcfg-menu 无法在启动时显示。

安装

注意: 2012-10-13版安装介质开始,安装程序已经默认安装systemdsystemd-sysvcompat
注意: 如果是在 VPS 中使用 Arch,请先阅读:Virtual_Private_Server#Moving_your_VPS_from_initscripts_to_systemd

本部分帮助还在使用sysvinitinitscripts 的用户迁移到systemd.

  1. 官方软件仓库安装 systemd 并添加内核参数init=/usr/lib/systemd/systemd
  2. systemctl enable daemonname 启用 /etc/rc.conf 中的守护进程。从 /etc/rc.conf 到 systemd 服务的转换可以参考:守护进程列表Services
  3. 重启系统,执行命令 cat /proc/1/comm,如果返回systemd,表示 systemd 已经正常启动。
  4. 确认主机名已经正确设置:hostnamectl set-hostname myhostname
  5. 删除 initscriptssysvinit,并安装systemd-sysvcompat.
  6. 可选,删除init=/usr/lib/systemd/systemd内核参数,现在已经不需要它了,systemd-sysvcompat提供了默认的 init.

附加信息

  • 如果内核参数中有 quiet,可以先删除它以便调试。
  • 使用 Systemd 的时候无需将用户加入optical, audio, scanner用户组。加入这些组反而会有问题,例如audio组会导致程序阻塞软件混声。每个 PAM 登录都拥有一个 logind 会话,它通过POSIX ACLs,赋予本地会话以声音设备访问权限、通过udisks挂载和卸载移动设备的权限等。
注意: 对于使用 startx -- vt7 进入X环境的用户,由于 logind 会话无法应用于X环境,用户必须加入这些组。
  • 如果卸载 initscriptsrc.conf 将不再有效。如果曾在其中设置了静态网络,或还未迁移到systemd的系统服务,请根据该节配置。
  • 如果 fstab 中有 LVM 设备,首次启动时会因为等待超时进入急救控制台。输入管理员密码,执行 systemctl enable lvm 启用相关服务,重启即可。

原生 systemd 配置文件

注意: 可能需要手动创建某些文件。所有文件的权限都是644,属主 root,属组 root。

主机名

主机名通过文件 /etc/hostname 进行配置。该文件不应包含系统的域名(如果有)。使用如下命令设置主机名:

# hostnamectl set-hostname myhostname

详情参见 man 5 hostnameman 1 hostnamectl

文件示例:

/etc/hostname
myhostname

本地化设置(locale)

系统默认 locale 记录在 /etc/locale.conf 文件中。通过如下命令配置:

# localectl set-locale LANG="zh_CN.utf8"
注意: 设置默认locale前,请确保已经生成该locale。方法是:在 /etc/locale.gen 中启用对应locale,然后以root权限执行 locale-gen

详情参见 man 1 localectlman 5 locale.conf

文件示例:

/etc/locale.conf
LANG=en_US.utf8

虚拟控制台

/etc/vconsole.conf 文件用来配置虚拟控制台,包括键盘布局和控制台字体:

/etc/vconsole.conf
KEYMAP=us
FONT=lat9w-16
FONT_MAP=8859-1_to_uni
注意: systemd-194 默认使用内核字体和键盘布局,因此以后不必在上述文件中留下空的 KEYMAP=FONT= 设置。

还可以通过命令设置键盘布局:

# localectl set-keymap de

该方法的优点是设置可以应用于X11: 详情参见 man 1 localectlman 5 vconsole.conf

时区

时区可通过创建适当的/etc/localtime符号链接来进行配置,该链接需指向目录/usr/share/zoneinfo/下的一个zoneinfo文件。也可执行以下命令直接完成这一操作:

# timedatectl set-timezone Asia/Shanghai

更多细节参见man 1 timedatectlman 5 localtimeman 7 archlinux

手动创建链接也行:

# ln -sf ../usr/share/zoneinfo/Asia/Shanghai /etc/localtime

旧的配置文件 /etc/timezone 已经没用了,可以安全删除。

硬件时钟

systemd 默认识别硬件时钟为协调世界时(UTC)。

提示: 推荐使用NTP服务来在线同步硬件时钟。

硬件时钟设定为地方时

将硬件时钟配置为地方时(不建议):

# timedatectl set-local-rtc true

重新调整为 UTC:

# timedatectl set-local-rtc false

如果设置成本地时间,处理夏令时有些麻烦。如果夏令时调整发生在关机时,下次启动时时间会出现问题(更多信息)。最新的内核直接从实时时钟芯片(RTC)读取时间,不使用 hwclock,内核把从 RTC 读取的时间当作 UTC 处理。所以如果硬件时间是地方时,系统启动一开始识别的时间是错误的,之后很快会进行矫正。这可能导致一些问题(尤其是时间倒退时)。

如果同时安装了 Windows 操作系统(默认使用地方时),那么一般 RTC 会被设置为地方时。Windows 其实也能处理 UTC,需要修改注册表。建议让 Windows 使用 UTC,而非让 Linux 使用地方时。Windows 使用 UTC 后,请记得禁用 Windows 的时间同步功能,以防 Windows 错误设置硬件时间。如上文所说,Linux 可以使用NTP服务来在线同步硬件时钟。

内核模块

目前,所有必要模块的加载均由 udev 自动完成。所以,如果不需要使用任何额外的模块,就没有必要在任何配置文件中添加启动时加载的模块。但是,有些情况下可能需要在系统启动时加载某个额外的模块,或者将某个模块列入黑名单以便使系统正常运行。

开机加载

systemd 读取 /etc/modules-load.d/ 中的配置加载额外的内核模块。配置文件名称通常为 /etc/modules-load.d/<program>.conf。格式很简单,一行一个要读取的模块名,而空行以及第一个非空格字符为#;的行会被忽略,如:

/etc/modules-load.d/virtio-net.conf
# Load virtio-net.ko at boot
virtio-net

另见man 5 modules-load.d

禁用内核模块

禁用内核模块的方法和 Arch 默认的 initscripts 相同,因为该过程实际由 kmod 处理。参见:Kernel modules (简体中文)#黑名单

文件系统挂载

默认行为是:在启动一个需要挂载特定分区的服务之前,系统自动检查并挂载分区。/etc/fstab 中设定的网络文件系统(如 NFSSamba)无需配置即可正常工作,systemd 将确保网络文件系统在网络链接就绪后挂载。

详情参阅:man 5 systemd.mount

自动挂载

  • 如果 /home 分区较大,可以让不依赖 /home 分区的服务先启动。把下面的参数添加到 /etc/fstab 文件中 /home 项目的参数部分即可:
noauto,x-systemd.automount

这样 /home 分区只有需要访问时才会被挂载。内核会缓存所有的文件操作,直到 /home 分区准备完成。

  • 挂载远程文件系统也是同理。如果你仅想在需要的时候才挂载,也可以添加 noauto,x-systemd.automount 参数。另外,可以设置 x-systemd.device-timeout=# 参数,设置超时时间,以防止网络资源不能访问的时候浪费时间。
  • 如果你的加密文件系统需要密钥,则需要添加 noauto 参数到 /etc/crypttab 文件中的对应位置。systemd 开机的时候就不会打开这个加密设备,会一直等待到设备被访问时再使用密钥文件挂载。比如在使用加密RAID设备的时候可以节省一定的时间,因为 systemd 不必等到设备可用后才能访问。例如:
/etc/crypttab
data /dev/md0 /root/key noauto

LVM

如果装有不通过 initramfs 激活的LVM卷,则需启动 lvm-monitoring 服务(由 lvm2 软件包提供):

# systemctl enable lvm-monitoring

类似地,如果LVM卷在加密设备上,并且启动后才激活,则需启动 lvm-on-crypt 服务(同样由 lvm2 软件包提供):

# systemctl enable lvm-on-crypt

ACPI 电源管理

systemd 能够处理某些电源相关的 ACPI 事件,通过 /etc/systemd/logind.conf 的下列选项配置:

  • HandlePowerKey:按下电源键后的动作
  • HandleSleepKey:按下挂起键后的动作
  • HandleHibernateKey: 按下休眠键后的动作
  • HandleLidSwitch:合上笔记本盖后待机

动作可以是 ignore, poweroff, reboot, halt, suspend, hibernatekexec.

系统默认设置为:

HandlePowerKey=poweroff
HandleSuspendKey=suspend
HandleHibernateKey=hibernate
HandleLidSwitch=suspend

如果不用图形界面,或者使用 i3awesome 这样简单的桌面管理器时,systemd 可以替代 acpid 处理 ACPI 事件。

注意: systemd 无法处理交流电源和电池 ACPI 事件,所以还得使用 Laptop Mode Toolsacpid 工具。

在当前版本的 systemd 中,这些 Handle 选项将会被应用到整个系统当中,除非它们被别的程序——例如某个桌面环境中的电源管理器——给“阻止”(inhibited)。如果其它的程序没有阻止这些 Handle ,你可能会先被 systemd 挂起你的系统,然后当系统被唤醒之后,电源管理器又会再次将系统挂起。

警告: 目前只有GNOMEKDE 支持 "inhibited" 命令。在其它的桌面管理器同样实现该功能之前,如果你想使用Xfceacpid 或者其它程序来管理 ACPI 事件,你需要把 Handle 选项设置为 ignore 。包含该功能的新版本还在开发当中。
注意: 除了内核默认的待机支持后端(用于处理待机/休眠),systemd 也可以使用其他后端(比如 UswsuspTuxOnIce)。

休眠时执行的脚本

使用 systemctl suspendsystemctl hibernatesystemctl hybrid-sleep 命令执行待机/休眠时,systemd 不会调用 pm-utilspm-utils 的钩子扩展(hook)——包括 自定义钩子——会失效。不过,systemd 提供了两种类似的待机/休眠时执行脚本的机制。

使用服务文件

可以将服务文件附在 suspend.target、hibernate.target 或 sleep.target 中,这样就能在待机/休眠前后执行某些操作。用户级操作和root/系统级操作应该使用不同的服务文件。要启用用户级服务文件,使用 # systemctl enable suspend@<用户名> && systemctl enable resume@<用户名>。例如:

/etc/systemd/system/suspend@.service
[Unit]
Description=User suspend actions
Before=sleep.target

[Service]
User=%I
Type=forking
Environment=DISPLAY=:0
ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop ; /usr/bin/mysql -e 'slave stop'
ExecStart=/usr/bin/sflock

[Install]
WantedBy=sleep.target
/etc/systemd/system/resume@.service
[Unit]
Description=User resume actions
After=suspend.target

[Service]
User=%I
Type=simple
ExecStartPre=/usr/local/bin/ssh-connect.sh
ExecStart=/usr/bin/mysql -e 'slave start'

[Install]
WantedBy=suspend.target

至于root/系统级服务(使用 # systemctl enable root-suspend 激活):

/etc/systemd/system/root-resume.service
[Unit]
Description=Local system resume actions
After=suspend.target

[Service]
Type=simple
ExecStart=/usr/bin/systemctl restart mnt-media.automount

[Install]
WantedBy=suspend.target
/etc/systemd/system/root-suspend.service
[Unit]
Description=Local system suspend actions
Before=sleep.target

[Service]
Type=simple
ExecStart=-/usr/bin/pkill sshfs

[Install]
WantedBy=sleep.target

上述服务文件的一些解释(详见 man systemd.service):

  • 如果设置 Type=OneShot,那么可以使用多个 ExecStart= 参数。否则只能写一个,替代方案是在 ExecStartPre 中添加命令,或使用分号分隔不同命令(见第一个例子,分号前后的空格都是必须的)。
  • 若命令前加上一个“-”(半角减号),则命令返回非零值时会被忽略、当作正常执行处理。
  • 有关调试,最好的方法是用 journalctl 查看日志。
使用 /usr/lib/systemd/system-sleep

systemd 在待机/休眠时执行 /usr/lib/systemd/system-sleep/ 里的所有脚本,传递下面两个参数:

  • 参数1:若是准备进入待机/休眠状态,则为 pre;唤醒时为 post
  • 参数2:事件名称,suspendhibernatehybrid-sleep

systemd 会同时执行所有脚本,而不是像 pm-utils 那样顺序执行。

脚本输出会记录在相关服务(systemd-suspend.servicesystemd-hibernate.servicesystemd-hybrid-sleep.service)中。通过日志查看:

# journalctl -b -u systemd-suspend

脚本示范:

/usr/lib/systemd/system-sleep/example.sh
#!/bin/sh
case $1/$2 in
  pre/*)
    echo "进入 $2 状态..."
    ;;
  post/*)
    echo "从 $2 状态唤醒..."
    ;;
esac

详情参见 man 7 systemd.specialman 8 systemd-sleep

临时文件

/usr/lib/tmpfiles.d//etc/tmpfiles.d/ 中的文件描述了 systemd-tmpfiles 如何创建、清理、删除临时文件和目录,这些文件和目录通常存放在 /run/tmp 中。配置文件名称为 /etc/tmpfiles.d/<program>.conf。此处的配置能覆盖 /usr/lib/tmpfiles.d/ 目录中的同名配置。

临时文件通常和服务文件同时提供,以生成守护进程需要的文件和目录。例如 Samba 服务需要目录 /var/run/samba 存在并设置正确的权限位,就象这样:

/usr/lib/tmpfiles.d/samba.conf
D /var/run/samba 0755 root root

此外,临时文件还可以用来在开机时向特定文件写入某些内容。比如,要禁止系统从USB设备唤醒,利用旧的 /etc/rc.local 可以用 echo USBE > /proc/acpi/wakeup,而现在可以这么做:

/etc/tmpfiles.d/disable-usb-wake.conf
w /proc/acpi/wakeup - - - - USBE

推荐使用新方法,因为 systemd 并不原生支持 /etc/rc.local

详情参见 man 4 tmpfiles.d

单元(unit)

一个单元配置文件可以描述如下内容之一:系统服务、socket、系统设备、挂载点、交换分区/文件、启动目标(target)、文件系统路径、由 systemd 管理的计时器。文件格式受 .desktop 文件启发,而最初起源是 Windows 下的 .ini 文件。

详情参阅 man 5 systemd.unit.

从 initscripts 迁移到 systemd

initscripts 模拟

initscripts 软件包提供了 systemd 和 Arch 传统配置的整合。当同时安装了initscripts和systemd时,若以systemd启动系统,systemd将执行以下操作:

  1. 解析/etc/rc.conf中的DAEMONS数组,并在系统启动时,启动所有列出的守护进程
  2. 在启动过程中执行/etc/rc.local
  3. 在系统关闭过程中执行/etc/rc.local.shutdown

Initscripts模拟仅仅是作为用户迁移到systemd时的过渡措施,这一方案最终将不再可行。原生的systemd并不依赖于rc.conf文件的集中式配置,因此推荐使用原生的systemd配置文件。原生systemd配置文件比/etc/rc.conf具有更高优先级。

注意: 替换/etc/rc.local的推荐方式是针对系统启动时要运行的程序编写自定义的service文件,详见相关章节.
注意: 如果你在/etc/inittab中禁用了以Template:Keypress重启系统,则需要以root执行systemctl mask ctrl-alt-del.target以使其对systemd重新生效。

迁移 DAEMONS 列表

若要用纯 systemd 环境,则应当删除 /etc/rc.conf 文件,并完全通过 systemctl 命令来启动服务。对于 DAEMONS 列表里面的每个 <服务名>,现在可以用以下命令设置成自动启动:

# systemctl enable <服务名>
提示: 这里有一份 initscripts 和 systemd 下常见服务的对应列表。

如果提示 <service_name>.service 不存在:

  • 很有可能是 systemd 用了不同的服务名。比如 crond 服务替换成 cronie.servicealsa 服务替换成了 alsa-store.servicealsa-restore.service 两个服务。另一个值得注意的是 network 服务,它被替换为一整套服务文件(详情参见 Configuring_Network_(简体中文))。
  • 另外,有些程序尚未提供 .service 文件,还得继续用 rc.conf 来配置开机自动启动。
提示: 用下面这个命令来查看已安装软件包包含的服务文件:
$ pacman -Ql cronie
[...]
cronie /etc/rc.d/crond                            # DAEMONS 列表中使用的 initscript 服务 (原生 systemd 配置中不再使用)
[...]
cronie /usr/lib/systemd/system/cronie.service     # 原生 systemd 服务文件
[...]
  • 有些服务不需要用户明确配置自启动。比如安装 dbus-core 软件包后 dbus.service 就会自动被配置为自启动。而 alsa-store.servicealsa-restore.service 也会由 systemd 自动启动。可以用 systemctl status <服务名> 命令来查看服务列表跟它们的运行状态。

systemd 基本工具

检视和控制systemd的主要命令是systemctl。该命令可用于查看系统状态和管理系统及服务。详见man 1 systemctl

提示: systemctl 参数中添加 -H <用户名>@<主机名> 可以实现对其他机器的远程控制。该过程使用 SSH 链接。
注意: systemadm 是 systemd 的官方图形前端。由 AUR 中的软件包 systemd-ui-gitAUR 提供。

分析系统状态

输出激活的单元:

$ systemctl

以下命令等效:

$ systemctl list-units

输出运行失败的单元:

$ systemctl --failed

所有可用的单元文件存放在 /usr/lib/systemd/system//etc/systemd/system/ 目录(后者优先级更高)。查看所有已安装服务:

$ systemctl list-unit-files

使用单元

一个单元可以是系统服务(.service)、挂载点(.mount)、sockets(.sockets)。

使用 systemctl 控制单元时,通常需要使用单元文件的全名,包括扩展名(例如 sshd.service)。但是有些单元可以在systemctl中使用简写方式。

  • 如果无扩展名,systemctl 默认把扩展名当作 .service。例如 netcfgnetcfg.service 是等价的。
  • 挂载点会自动转化为相应的 .mount 单元。例如 /home 等价于 home.mount
  • 设备会自动转化为相应的 .device 单元,所以 /dev/sda2 等价于 dev-sda2.device

立即激活单元:

# systemctl start <单元>

立即停止单元:

# systemctl stop <单元>

重启单元:

# systemctl restart <单元>

命令单元重新读取配置:

# systemctl reload <单元>

输出单元运行状态:

$ systemctl status <单元>

检查单元是否配置为自动启动:

$ systemctl is-enabled <单元>

开机自动激活单元:

# systemctl enable <单元>
注意: 如果服务没有Install段落,一般意味着应该通过其它服务自动调用它们。如果真的需要手动安装,可以直接连接服务,如下(将foo替换为真实的服务名):
# ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/

取消开机自动激活单元:

# systemctl disable <单元>}}

显示单元的手册页(必须由单元文件提供):

# systemctl help <单元>

重新载入 systemd,扫描新的或有变动的单元:

# systemctl daemon-reload

电源管理

如果你正登录在一个本地的systemd-logind用户会话,且当前没有其它活动的会话,那么以下命令无需root权限即可执行。否则(例如,当前有另一个用户登录在某个tty),systemd 将会自动请求输入root密码。

重启:

$ systemctl reboot

退出系统并停止电源:

$ systemctl poweroff

待机:

$ systemctl suspend

休眠:

$ systemctl hibernate

混合休眠模式(同时休眠到硬盘并待机):

$ systemctl hybrid-sleep

启动桌面环境

使用登录管理器

通过启动登录管理器(或称显示管理器),即可进行图形界面登录。目前,Arch 提供了 GDMKDMSLiMXDMLXDMLightDM 的 systemd 服务文件。以 KDM 为例,配置开机启动:

# systemctl enable kdm.service

执行上述命令后,登录管理器应当能正常工作了。如果不是的话,很可能是因为你修改了default.target。默认情况应当如下:

# ls -l /etc/systemd/system/default.target
/etc/systemd/system/default.target -> /usr/lib/systemd/system/graphical.target

删除被修改的 default.target 即可,systemd 会自动使用默认配置(即 graphical.target):

# rm /etc/systemd/system/default.target

使用 systemd-logind

注意: 自 2012-10-30 起, ConsoleKit 已被 systemd-logind 取代 ,作为登录到桌面环境的默认方式。

可使用 loginctl 来查看用户会话的状态。所有 PolicyKit 操作,如挂起系统、挂载外部驱动器,都无需配置即可使用。

$ loginctl show-session $XDG_SESSION_ID

自己编写 .service 文件

参见:Systemd/Services

处理依赖关系

使用systemd时,可通过正确编写单元配置文件来解决其依赖关系。典型的情况是,单元A要求单元BA启动之前运行。在此情况下,向单元A配置文件中的 [Unit] 段添加 Requires=BAfter=B 即可。若此依赖关系是可选的,可添加 Wants=BAfter=B。请注意 Wants=Requires= 并不意味着 After=,即如果 After= 选项没有制定,这两个单元将被并行启动。

依赖关系通常被用在服务(service)而不是目标(target)上。例如, network.target 一般会被某个配置网络接口的服务引入,所以,将自定义的单元排在该服务之后即可,因为 network.target 已经启动。

启动方式

编写自定义的service文件时,可以选择几种不同的服务启动方式。启动方式可通过配置文件 [Service] 段中的 Type= 参数进行设置。具体的参数说明请参阅 man systemd.service

  • Type=simple:systemd认为该服务将立即启动。服务进程不会fork。如果该服务要启动其他服务,不要使用此类型启动,除非该服务是socket激活型。
  • Type=forking:systemd认为当该服务进程fork,且父进程退出后服务启动成功。对于常规的守护进程(daemon),除非你确定此启动方式无法满足需求,使用此类型启动即可。使用此启动类型应同时指定 PIDFile=,以便systemd能够跟踪服务的主进程。
  • Type=oneshot:这一选项适用于只执行一项任务随后退出的服务。你可能需要同时设置 RemainAfterExit=yes 使得 systemd 在服务进程退出之后仍然认为服务处于激活状态。
  • Type=notify:与 Type=simple 相同,但约定服务会在就绪后向 systemd 发送一个信号。这一通知的实现由 libsystemd-daemon.so 提供。
  • Type=dbus:若以此方式启动,当指定的 BusName 出现在DBus系统总线上时,systemd认为服务就绪。

替换现存单元文件

目录 /etc/systemd/system/ 中的单元配置文件比 /usr/lib/systemd/system/ 目录下的文件拥有更高优先级。 若需要定制某个单元的启动(使配置不受软件包更新的影响),请将现有的单元配置文件从 /usr/lib/ 复制到 /etc/ 目录下,并在此目录中修改。或者,可以使用 .include 来解析一个现有的配置文件,并覆盖原选项或添加新选项。例如,若想要某个服务的配置文件中添加额外依赖关系,可以编写:

/etc/systemd/system/<服务名>.service
.include /usr/lib/systemd/system/<服务名>.service

[Unit]
Requires=<新依赖>
After=<新依赖>

然后运行以下命令使更改生效:

# systemctl reenable <单元>
# systemctl restart <单元>
提示: 可以用 systemd-delta 命令来查看哪些单元文件被覆盖、哪些被修改。

单元配置文件的 vim 语法高亮支持

可从 官方仓库 安装 vim-systemd 软件包,使 unit 配置文件在 Vim 下支持语法高亮。

目标(target)

启动级别(runlevel)是一个旧的概念。现在,systemd 引入了一个和启动级别功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每个目标都有名字和独特的功能,并且能同时启用多个。一些目标继承其他目标的服务,并启动新服务。systemd 提供了一些模仿 sysvinit 启动级别的目标,仍可以使用旧的 telinit 启动级别 命令切换。

获取当前目标

不要使用 runlevel 命令了:

$ systemctl list-units --type=target

创建新目标

在 Fedora 中,启动级别 0、1、3、5、6 都被赋予特定用途,并且都对应一个 systemd 的目标。然而,没有什么很好的移植用户定义的启动级别(2、4)的方法。要实现类似功能,可以以原有的启动级别为基础,创建一个新的目标 /etc/systemd/system/<新目标>(可以参考 /usr/lib/systemd/system/graphical.target),创建 /etc/systemd/system/<新目标>.wants 目录,向其中加入额外服务的链接(指向 /usr/lib/systemd/system/ 中的单元文件)。

目标表

SysV 启动级别 Systemd 目标 注释
0 runlevel0.target, poweroff.target 中断系统(halt)
1, s, single runlevel1.target, rescue.target 单用户模式
2, 4 runlevel2.target, runlevel4.target, multi-user.target 用户自定义启动级别,通常识别为级别3。
3 runlevel3.target, multi-user.target 多用户,无图形界面。用户可以通过终端或网络登录。
5 runlevel5.target, graphical.target 多用户,图形界面。继承级别3的服务,并启动图形界面服务。
6 runlevel6.target, reboot.target 重启
emergency emergency.target 急救模式(Emergency shell)

切换启动级别/目标

systemd 中,启动级别通过“目标单元”访问。通过如下命令切换:

# systemctl isolate graphical.target

该命令对下次启动无影响。等价于telinit 3telinit 5

修改默认启动级别/目标

开机启动进的目标是 default.target,默认链接到 graphical.target (大致相当于原来的启动级别5)。可以通过内核参数更改默认启动级别:

提示: 可以省略扩展名 .target
  • systemd.unit=multi-user.target (大致相当于级别3)
  • systemd.unit=rescue.target (大致相当于级别1)

另一个方法是修改 default.target。可以通过 systemctl 修改它:

# systemctl enable multi-user.target

命令执行情况由 systemctl 显示:链接 /etc/systemd/system/default.target 被创建,指向新的默认启动级别。该方法当且仅当目标配置文件中有以下内容时有效:

[Install]
Alias=default.target

目前,multi-user.targetgraphical.target 都包含这段内容。

日志

自版本 38 起,systemd 提供了自己日志系统(logging system),称为 journal. 使用 systemd 日志,无需额外安装日志服务(syslog)。读取日志的命令:

# journalctl

默认情况下(当 Storage= 在文件 /etc/systemd/journald.conf 中被设置为 auto),日志记录将被写入 /var/log/journal/。若目录 /var/log/journal/ 不存在(例如,被用户或某个程序删除),systemd将不会自动创建它,而是将日志记录写入 /run/systemd/journal。这意味着,系统重启后日志将丢失。

过滤输出

journalctl可以根据特定字段过滤输出,例如:

显示本次启动后的所有日志:

# journalctl -b

不过,一般大家更关心的不是本次启动后的日志,而是上次启动时的(例如,刚刚系统崩溃了)。目前还没有这项功能,正在 systemd-devel@lists.freedesktop.org 讨论中。

目前的折中方案是:

# journalctl --since=today | tac | sed -n '/-- Reboot --/{n;:r;/-- Reboot --/q;p;n;b r}' | tac

以上命令输出本日内的所有启动信息。但要注意,如果日志很多,该命令执行时间会比较漫长。

动态跟踪最新信息:

# journalctl -f

显示特定程序的所有消息:

# journalctl /usr/lib/systemd/systemd

显示特定进程的所有消息:

# journalctl _PID=1

显示指定单元的所有消息:

# journalctl -u netcfg

详情参阅man journalctlman systemd.journal-fields,以及 Lennert 的这篇博文

日志大小限制

如果按上面的操作保留日志的话,默认日志最大限制为所在文件系统容量的 10%,即:如果 /var/log/journal 储存在 50GiB 的根分区中,那么日志最多存储 5GiB 数据。可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 来指定该最大限制。如限制日志最大 50MiB:

SystemMaxUse=50M

详情参见 man journald.conf.

配合 syslog 使用

systemd 提供了 socket /run/systemd/journal/syslog,以兼容传统日志服务。所有系统信息都会被传入。要使传统日志服务工作,需要让服务链接该 socket,而非 /dev/log官方说明)。Arch 软件仓库中的 syslog-ng 已经包含了需要的配置。

设置开机启动 syslog-ng:

 # systemctl enable syslog-ng

优化

参阅:Improve Boot Performance (简体中文)

启动过程分析

systemd 提供了一个分析启动过程的工具 —— systemd-analyze。可以用它看看哪些单元拖慢了开机过程,并据此进行优化。安装 python2-dbuspython2-cairo 软件包后该工具才能工作。

查看开机过程在内核/用户空间消耗的时间:

$ systemd-analyze
提示: 如果在 /etc/mkinitcpio.confHOOKS 数组添加 timestamp,并重新生成启动内存镜像(mkinitcpio -p linux),systemd-analyze 还可以显示处理该启动镜像花费的时间。

按照耗费时间顺序,输出启动每个单元耗费的时间:

$ systemd-analyze blame

生成类似于 bootchart 的开机过程图表:

$ systemd-analyze plot > plot.svg

使用 bootchart

由于没有办法在内核参数设置两个 init,所以不能使用源里的 bootchart。不过,AUR 软件包 bootchart2AUR 提供了一个的 systemd 服务,安装后启用即可:

# systemctl enable bootchart.service

详情参阅 bootchart 文档

预读

systemd 自己实现了一个 readahead,可以用来提高开机效率。不过,效果会因内核版本和硬件情况而不同(极少数情况下还会变慢)。开启 readahead:

# systemctl enable systemd-readahead-collect.service systemd-readahead-replay.service

要知道,readahead 的超级牛力只有在重启几次后才会显现。

疑难解答

启动/重启服务时出现 "Error: No space left on device"

参见:CrashPlan Support

关机/重启十分缓慢

如果关机特别慢(甚至跟死机了一样),很可能是某个拒不退出的服务在作怪。systemd 会等待一段时间,然后再尝试杀死它。请阅读这篇文章,确认你是否是该问题受害者。

短时进程无日志记录

systemctl -u foounit.service 没有显示某个短时进程的任何输出,那么改用 PID 试试。例如,若 systemd-modules-load.service 执行失败,那么先用 systemctl status systemd-modules-load 查询其 PID(比如是123),然后检索该 PID 相关的日志 journalctl -b _PID=123。运行时进程的日志元数据(诸如 _SYSTEMD_UNIT 和 _COMM)被乱序收集在 /proc 目录。要修复该问题,必须修改内核,使其通过套接字连接来提供上述数据,该过程类似于 SCM_CREDENTIALS。

相关资源