systemd详解详解

systemd详解

CentOS 7 使用systemd替换了SysV。Systemd目的是要取代Unix时代以来一直在使用的init系统,兼容SysV和LSB的启动脚本,并且够在进程启动过程当中更有效地引导加载服务。php

systemd的特性有:html

  • 支持并行化任务
  • 同时采用socket式与D-Bus总线式激活服务;
  • 按需启动守护进程(daemon);
  • 利用 Linux 的 cgroups 监视进程;
  • 支持快照和系统恢复;
  • 维护挂载点和自动挂载点;
  • 各服务间基于依赖关系进行精密控制。

systemd基本工具

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

小贴士:linux

  • 在 systemctl 参数中添加 -H <用户名>@<主机名> 能够实现对其余机器的远程控制。该过程使用ssh连接。
  • systemadm是systemd 的官方图形前端

分析系统状态

输出激活的单元:web

  1. $ systemctl

如下命令等效:shell

  1. $ systemctl list-units

输出运行失败的单元:vim

  1. $ systemctl --failed

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

  1. $ systemctl list-unit-files

使用单元

一个单元配置文件能够描述以下内容之一:系统服务(.service)、挂载点(.mount)、sockets(.sockets) 、系统设备(.device)、交换分区(.swap)、文件路径(.path)、启动目标(.target)、由 systemd 管理的计时器(.timer)。详情参阅 man 5 systemd.unit。ssh

使用 systemctl 控制单元时,一般须要使用单元文件的全名,包括扩展名(例如 sshd.service)。可是有些单元能够在systemctl中使用简写方式。socket

  • 若是无扩展名,systemctl 默认把扩展名看成 .service。例如 netcfg 和 netcfg.service 是等价的。
  • 挂载点会自动转化为相应的 .mount 单元。例如 /home 等价于 home.mount。
  • 设备会自动转化为相应的 .device 单元,因此 /dev/sda2 等价于 dev-sda2.device。

注: 有一些单元的名称包含一个 @ 标记, (e.g. name@string.service): 这意味着它是模板单元 name@.service 的一个 实例。 string 被称做实例标识符, 在 systemctl 调用模板单元时,会将其看成一个参数传给模板单元,模板单元会使用这个传入的参数代替模板中的 %I 指示符。 在实例化以前,systemd 会先检查 name@string.suffix 文件是否存在(若是存在,应该就是直接使用这个文件,而不是模板实例化了)。大多数状况下,包换 @ 标记都意味着这个文件是模板。若是一个模板单元没有实例化就调用,该调用会返回失败,由于模板单元中的 %I 指示符没有被替换。

当即激活单元:

  1. # systemctl start <单元>

当即中止单元:

  1. # systemctl stop <单元>

重启单元:

  1. # systemctl restart <单元>

命令单元从新读取配置:

  1. # systemctl reload <单元>

输出单元运行状态:

  1. $ systemctl status <单元>

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

  1. $ systemctl is-enabled <单元>

开机自动激活单元:

  1. # systemctl enable <单元>

注意: 若是服务没有Install段落,通常意味着应该经过其它服务自动调用它们。若是真的须要手动安装,能够直接链接服务,以下(将foo替换为真实的服务名):

  1. # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/

取消开机自动激活单元:

  1. # systemctl disable <单元>

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

  1. # systemctl help <单元>

从新载入 systemd,扫描新的或有变更的单元:

  1. # systemctl daemon-reload

电源管理

安装 polkit 后才可以使用电源管理。

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

重启:

  1. $ systemctl reboot

退出系统并中止电源:

  1. $ systemctl poweroff

待机:

  1. $ systemctl suspend

休眠:

  1. $ systemctl hibernate

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

  1. $ systemctl hybrid-sleep

编写单元文件

systemd单元文件的语法来源于 XDG桌面入口配置文件.desktop文件,最初的源头则是Microsoft Windows的.ini文件。单元文件能够从两个地方加载,优先级从低到高分别是:

  • /usr/lib/systemd/system/: 软件包安装的单元
  • /etc/systemd/system/: 系统管理员安装的单元

注意: 当systemd运行在用户模式下时,使用的加载路径是彻底不一样的。

单元文件的语法,能够参考系统已经安装的单元,也能够参考man systemd.service中的EXAMPLES章节

小贴士: 以 # 开头的注释可能也能用在 unit-files 中, 可是只能在新行中使用。 不要在 systemd 的参数后面使用行末注释, 不然 unit 将会启动失败。

处理依赖关系

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

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

服务类型

编写自定义的 service 文件时,能够选择几种不一样的服务启动方式。启动方式可经过配置文件 [Service] 段中的 Type= 参数进行设置。

  • 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认为服务就绪。
  • Type=idle: systemd会等待全部任务(Jobs)处理完成后,才开始执行idle类型的单元。除此以外,其余行为和Type=simple 相似。

type的更多解释能够参考 systemd.service(5)

修改现存单元文件

要更改由软件包提供的单元文件,先建立名为 /etc/systemd/system/<单元名>.d/ 的目录(如 /etc/systemd/system/httpd.service.d/),而后放入 *.conf 文件,其中能够添加或重置参数。这里设置的参数优先级高于原来的单元文件。例如,若是想添加一个额外的依赖,建立这么一个文件便可:

  1. /etc/systemd/system/<unit>.d/customdependency.conf
  2. [Unit]
  3. Requires=<新依赖>
  4. After=<新依赖>

其它举例,

  1. /etc/systemd/system/unit.d/customexec.conf
  2. [Service]
  3. ExecStartExecStart=
  4. ExecStart=new command

想知道为何修改 ExecStart 前必须将其置空

下面是自动重启服务的一个例子:

  1. /etc/systemd/system/unit.d/restart.conf
  2. [Service]
  3. Restart=always
  4. RestartSec=30

而后运行如下命令使更改生效:

  1. # systemctl daemon-reload
  2. # systemctl restart <单元>

此外,把旧的单元文件从 /usr/lib/systemd/system/ 复制到 /etc/systemd/system/,而后进行修改,也能够达到一样效果。在 /etc/systemd/system/ 目录中的单元文件的优先级老是高于 /usr/lib/systemd/system/ 目录中的同名单元文件。注意,当 /usr/lib/ 中的单元文件因软件包升级变动时,/etc/ 中自定义的单元文件不会同步更新。此外,你还得执行 systemctl reenable <unit>,手动从新启用该单元。所以,建议使用前面一种利用 *.conf 的方法。

小贴士: 用 systemd-delta 命令来查看哪些单元文件被覆盖、哪些被修改。系统维护的时候须要及时了解哪些单元已经有了更新

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

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

目标(target)

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

不要使用 runlevel 命令了:

  1. $ systemctl list-units --type=target

建立新目标

在 Fedora 中,启动级别 0、一、三、五、6 都被赋予特定用途,而且都对应一个 systemd 的目标。然而,没有什么很好的移植用户定义的启动级别(二、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 中,启动级别经过“目标单元”访问。经过以下命令切换:

  1. # systemctl isolate graphical.target

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

修改默认启动级别/目标

开机启动进的目标是 default.target,默认连接到 graphical.target (大体至关于原来的启动级别5)。能够经过内核参数更改默认启动级别:

小贴士: 能够省略扩展名 .target。

  •  systemd.unit=multi-user.target (大体至关于级别3)
  •  systemd.unit=rescue.target (大体至关于级别1)

另外一个方法是修改 default.target。能够经过 systemctl 修改它:

  1. # systemctl enable multi-user.target

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

  1. [Install]
  2. Alias=default.target

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

临时文件

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

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

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

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

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

详情参见 man 5 tmpfiles.d。

注意: 该方法不能向 /sys 中的配置文件添加参数,由于 systemd-tmpfiles-setup 有可能在相关模块加载前运行。这种状况下,须要首先经过 modinfo <模块名> 确认须要的参数,并在 /etc/modprobe.d 下的一个文件中设置改参数。另外,还可使用 udev 规则,在设备就绪时设置相应属性。

定时器

定时器是以 .timer 为后缀的配置文件,记录由system的里面由时间触发的动做, 定时器能够替代 cron 的大部分功能。

日志

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

  1. # journalctl

默认状况下(当 Storage= 在文件 /etc/systemd/journald.conf 中被设置为 auto),日志记录将被写入 /var/log/journal/。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动建立它,直到下次升级软件包时重建该目录。若是该目录缺失,systemd 会将日志记录写入 /run/systemd/journal。这意味着,系统重启后日志将丢失。

Tip: 若是 /var/log/journal/ 位于 btrfs 文件系统,应该考虑对这个目录禁用写入时复制

过滤输出

journalctl能够根据特定字段过滤输出,例如:

显示本次启动后的全部日志:

  1. # journalctl -b

不过,通常你们更关心的不是本次启动后的日志,而是上次启动时的(例如,刚刚系统崩溃了)。可使用 -b 参数:

  • journalctl -b -0 显示本次启动的信息
  • journalctl -b -1 显示上次启动的信息
  • journalctl -b -2 显示上上次启动的信息 journalctl -b -2
  • Show all messages from date (and optional time):
  1. # journalctl --since="2012-10-30 18:17:16"
  • Show all messages since 20 minutes ago:
  1. # journalctl --since "20 min ago"
  • 显示最新信息
  1. # journalctl -f
  • 显示特定程序的全部消息:
  1. # journalctl /usr/lib/systemd/systemd
  • 显示特定进程的全部消息:
  1. # journalctl _PID=1
  • 显示指定单元的全部消息:
  1. # journalctl -u netcfg
  • Show kernel ring buffer:
  1. # journalctl -k
  • Show auth.log equivalent by filtering on syslog facility:
  1. # journalctl -f -l SYSLOG_FACILITY=10

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

日志大小限制

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

  1. SystemMaxUse=50M

详情参见 man journald.conf.

配合syslog使用

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

设置开机启动 syslog-ng:

  1. # systemctl enable syslog-ng

这里有一份很不错的 journalctl指南。

Forward journald to /dev/tty12

In /etc/systemd/journald.conf enable the following:

  1. ForwardToConsole=yes
  2. TTYPath=/dev/tty12
  3. MaxLevelConsole=info

重启journald:

  1. # systemctl restart systemd-journald

疑难解答

关机/重启十分缓慢

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

短时进程无日志记录

若 journalctl -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。

诊断启动问题

使用以下内核参数引导: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M

禁止在程序崩溃时转储内存

要使用老的内核转储,建立下面文件:

  1. /etc/sysctl.d/49-coredump.conf
  2. kernel.core_pattern = core
  3. kernel.core_uses_pid = 0

而后运行:

  1. # /usr/lib/systemd/systemd-sysctl

一样可能须要执行"unlimit"设置文件大小:

  1. $ ulimit -c unlimited
Sun Jul 20 23:00:16 CST 2014

systemd详解

CentOS 7 使用systemd替换了SysV。Systemd目的是要取代Unix时代以来一直在使用的init系统,兼容SysV和LSB的启动脚本,并且够在进程启动过程当中更有效地引导加载服务。

systemd的特性有:

  • 支持并行化任务
  • 同时采用socket式与D-Bus总线式激活服务;
  • 按需启动守护进程(daemon);
  • 利用 Linux 的 cgroups 监视进程;
  • 支持快照和系统恢复;
  • 维护挂载点和自动挂载点;
  • 各服务间基于依赖关系进行精密控制。

systemd基本工具

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

小贴士:

  • 在 systemctl 参数中添加 -H <用户名>@<主机名> 能够实现对其余机器的远程控制。该过程使用ssh连接。
  • systemadm是systemd 的官方图形前端

分析系统状态

输出激活的单元:

  1. $ systemctl

如下命令等效:

  1. $ systemctl list-units

输出运行失败的单元:

  1. $ systemctl --failed

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

  1. $ systemctl list-unit-files

使用单元

一个单元配置文件能够描述以下内容之一:系统服务(.service)、挂载点(.mount)、sockets(.sockets) 、系统设备(.device)、交换分区(.swap)、文件路径(.path)、启动目标(.target)、由 systemd 管理的计时器(.timer)。详情参阅 man 5 systemd.unit。

使用 systemctl 控制单元时,一般须要使用单元文件的全名,包括扩展名(例如 sshd.service)。可是有些单元能够在systemctl中使用简写方式。

  • 若是无扩展名,systemctl 默认把扩展名看成 .service。例如 netcfg 和 netcfg.service 是等价的。
  • 挂载点会自动转化为相应的 .mount 单元。例如 /home 等价于 home.mount。
  • 设备会自动转化为相应的 .device 单元,因此 /dev/sda2 等价于 dev-sda2.device。

注: 有一些单元的名称包含一个 @ 标记, (e.g. name@string.service): 这意味着它是模板单元 name@.service 的一个 实例。 string 被称做实例标识符, 在 systemctl 调用模板单元时,会将其看成一个参数传给模板单元,模板单元会使用这个传入的参数代替模板中的 %I 指示符。 在实例化以前,systemd 会先检查 name@string.suffix 文件是否存在(若是存在,应该就是直接使用这个文件,而不是模板实例化了)。大多数状况下,包换 @ 标记都意味着这个文件是模板。若是一个模板单元没有实例化就调用,该调用会返回失败,由于模板单元中的 %I 指示符没有被替换。

当即激活单元:

  1. # systemctl start <单元>

当即中止单元:

  1. # systemctl stop <单元>

重启单元:

  1. # systemctl restart <单元>

命令单元从新读取配置:

  1. # systemctl reload <单元>

输出单元运行状态:

  1. $ systemctl status <单元>

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

  1. $ systemctl is-enabled <单元>

开机自动激活单元:

  1. # systemctl enable <单元>

注意: 若是服务没有Install段落,通常意味着应该经过其它服务自动调用它们。若是真的须要手动安装,能够直接链接服务,以下(将foo替换为真实的服务名):

  1. # ln -s /usr/lib/systemd/system/foo.service /etc/systemd/system/graphical.target.wants/

取消开机自动激活单元:

  1. # systemctl disable <单元>

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

  1. # systemctl help <单元>

从新载入 systemd,扫描新的或有变更的单元:

  1. # systemctl daemon-reload

电源管理

安装 polkit 后才可以使用电源管理。

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

重启:

  1. $ systemctl reboot

退出系统并中止电源:

  1. $ systemctl poweroff

待机:

  1. $ systemctl suspend

休眠:

  1. $ systemctl hibernate

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

  1. $ systemctl hybrid-sleep

编写单元文件

systemd单元文件的语法来源于 XDG桌面入口配置文件.desktop文件,最初的源头则是Microsoft Windows的.ini文件。单元文件能够从两个地方加载,优先级从低到高分别是:

  • /usr/lib/systemd/system/: 软件包安装的单元
  • /etc/systemd/system/: 系统管理员安装的单元

注意: 当systemd运行在用户模式下时,使用的加载路径是彻底不一样的。

单元文件的语法,能够参考系统已经安装的单元,也能够参考man systemd.service中的EXAMPLES章节

小贴士: 以 # 开头的注释可能也能用在 unit-files 中, 可是只能在新行中使用。 不要在 systemd 的参数后面使用行末注释, 不然 unit 将会启动失败。

处理依赖关系

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

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

服务类型

编写自定义的 service 文件时,能够选择几种不一样的服务启动方式。启动方式可经过配置文件 [Service] 段中的 Type= 参数进行设置。

  • 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认为服务就绪。
  • Type=idle: systemd会等待全部任务(Jobs)处理完成后,才开始执行idle类型的单元。除此以外,其余行为和Type=simple 相似。

type的更多解释能够参考 systemd.service(5)

修改现存单元文件

要更改由软件包提供的单元文件,先建立名为 /etc/systemd/system/<单元名>.d/ 的目录(如 /etc/systemd/system/httpd.service.d/),而后放入 *.conf 文件,其中能够添加或重置参数。这里设置的参数优先级高于原来的单元文件。例如,若是想添加一个额外的依赖,建立这么一个文件便可:

  1. /etc/systemd/system/<unit>.d/customdependency.conf
  2. [Unit]
  3. Requires=<新依赖>
  4. After=<新依赖>

其它举例,

  1. /etc/systemd/system/unit.d/customexec.conf
  2. [Service]
  3. ExecStartExecStart=
  4. ExecStart=new command

想知道为何修改 ExecStart 前必须将其置空

下面是自动重启服务的一个例子:

  1. /etc/systemd/system/unit.d/restart.conf
  2. [Service]
  3. Restart=always
  4. RestartSec=30

而后运行如下命令使更改生效:

  1. # systemctl daemon-reload
  2. # systemctl restart <单元>

此外,把旧的单元文件从 /usr/lib/systemd/system/ 复制到 /etc/systemd/system/,而后进行修改,也能够达到一样效果。在 /etc/systemd/system/ 目录中的单元文件的优先级老是高于 /usr/lib/systemd/system/ 目录中的同名单元文件。注意,当 /usr/lib/ 中的单元文件因软件包升级变动时,/etc/ 中自定义的单元文件不会同步更新。此外,你还得执行 systemctl reenable <unit>,手动从新启用该单元。所以,建议使用前面一种利用 *.conf 的方法。

小贴士: 用 systemd-delta 命令来查看哪些单元文件被覆盖、哪些被修改。系统维护的时候须要及时了解哪些单元已经有了更新

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

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

目标(target)

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

不要使用 runlevel 命令了:

  1. $ systemctl list-units --type=target

建立新目标

在 Fedora 中,启动级别 0、一、三、五、6 都被赋予特定用途,而且都对应一个 systemd 的目标。然而,没有什么很好的移植用户定义的启动级别(二、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 中,启动级别经过“目标单元”访问。经过以下命令切换:

  1. # systemctl isolate graphical.target

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

修改默认启动级别/目标

开机启动进的目标是 default.target,默认连接到 graphical.target (大体至关于原来的启动级别5)。能够经过内核参数更改默认启动级别:

小贴士: 能够省略扩展名 .target。

  •  systemd.unit=multi-user.target (大体至关于级别3)
  •  systemd.unit=rescue.target (大体至关于级别1)

另外一个方法是修改 default.target。能够经过 systemctl 修改它:

  1. # systemctl enable multi-user.target

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

  1. [Install]
  2. Alias=default.target

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

临时文件

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

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

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

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

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

详情参见 man 5 tmpfiles.d。

注意: 该方法不能向 /sys 中的配置文件添加参数,由于 systemd-tmpfiles-setup 有可能在相关模块加载前运行。这种状况下,须要首先经过 modinfo <模块名> 确认须要的参数,并在 /etc/modprobe.d 下的一个文件中设置改参数。另外,还可使用 udev 规则,在设备就绪时设置相应属性。

定时器

定时器是以 .timer 为后缀的配置文件,记录由system的里面由时间触发的动做, 定时器能够替代 cron 的大部分功能。

日志

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

  1. # journalctl

默认状况下(当 Storage= 在文件 /etc/systemd/journald.conf 中被设置为 auto),日志记录将被写入 /var/log/journal/。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动建立它,直到下次升级软件包时重建该目录。若是该目录缺失,systemd 会将日志记录写入 /run/systemd/journal。这意味着,系统重启后日志将丢失。

Tip: 若是 /var/log/journal/ 位于 btrfs 文件系统,应该考虑对这个目录禁用写入时复制

过滤输出

journalctl能够根据特定字段过滤输出,例如:

显示本次启动后的全部日志:

  1. # journalctl -b

不过,通常你们更关心的不是本次启动后的日志,而是上次启动时的(例如,刚刚系统崩溃了)。可使用 -b 参数:

  • journalctl -b -0 显示本次启动的信息
  • journalctl -b -1 显示上次启动的信息
  • journalctl -b -2 显示上上次启动的信息 journalctl -b -2
  • Show all messages from date (and optional time):
  1. # journalctl --since="2012-10-30 18:17:16"
  • Show all messages since 20 minutes ago:
  1. # journalctl --since "20 min ago"
  • 显示最新信息
  1. # journalctl -f
  • 显示特定程序的全部消息:
  1. # journalctl /usr/lib/systemd/systemd
  • 显示特定进程的全部消息:
  1. # journalctl _PID=1
  • 显示指定单元的全部消息:
  1. # journalctl -u netcfg
  • Show kernel ring buffer:
  1. # journalctl -k
  • Show auth.log equivalent by filtering on syslog facility:
  1. # journalctl -f -l SYSLOG_FACILITY=10

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

日志大小限制

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

  1. SystemMaxUse=50M

详情参见 man journald.conf.

配合syslog使用

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

设置开机启动 syslog-ng:

  1. # systemctl enable syslog-ng

这里有一份很不错的 journalctl指南。

Forward journald to /dev/tty12

In /etc/systemd/journald.conf enable the following:

  1. ForwardToConsole=yes
  2. TTYPath=/dev/tty12
  3. MaxLevelConsole=info

重启journald:

  1. # systemctl restart systemd-journald

疑难解答

关机/重启十分缓慢

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

短时进程无日志记录

若 journalctl -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。

诊断启动问题

使用以下内核参数引导: systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M

禁止在程序崩溃时转储内存

要使用老的内核转储,建立下面文件:

  1. /etc/sysctl.d/49-coredump.conf
  2. kernel.core_pattern = core
  3. kernel.core_uses_pid = 0

而后运行:

  1. # /usr/lib/systemd/systemd-sysctl

一样可能须要执行"unlimit"设置文件大小:

  1. $ ulimit -c unlimited
Sun Jul 20 23:00:16 CST 2014