systemd
From the project web page
- systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system. systemd provides aggressive parallelization capabilities, uses socket and D-Bus activation for starting services, offers on-demand starting of daemons, keeps track of processes using Linux control groups, maintains mount and automount points, and implements an elaborate transactional dependency-based service control logic. systemd supports SysV and LSB init scripts and works as a replacement for sysvinit. Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution.
Historically, what systemd calls "service" was named daemon: any program that runs as a "background" process (without a terminal or user interface), commonly waiting for events to occur and offering services. A good example is a web server that waits for a request to deliver a page, or an ssh server waiting for someone trying to log in. While these are full featured applications, there are daemons whose work is not that visible. Daemons are for tasks like writing messages into a log file (e.g. syslog
, metalog
) or keeping your system time accurate (e.g. ntpd). For more information see daemon(7).
Basic systemctl usage
The main command used to introspect and control systemd is systemctl. Some of its uses are examining the system state and managing the system and services. See systemctl(1) for more details.
- You can use all of the following systemctl commands with the
-H user@host
switch to control a systemd instance on a remote machine. This will use SSH to connect to the remote systemd instance. - Plasma users can install systemdgenie as a graphical frontend for systemctl. After installing, the module will be added under System.
Using units
Units commonly include, but are not limited to, services (.service), mount points (.mount), devices (.device) and sockets (.socket).
When using systemctl, you generally have to specify the complete name of the unit file, including its suffix, for example sshd.socket
. There are however a few short forms when specifying the unit in the following systemctl commands
- If you do not specify the suffix, systemctl will assume .service. For example,
netctl
andnetctl.service
are equivalent. - Mount points will automatically be translated into the appropriate .mount unit. For example, specifying
/home
is equivalent tohome.mount
. - Similar to mount points, devices are automatically translated into the appropriate .device unit, therefore specifying
/dev/sda2
is equivalent todev-sda2.device
.
See systemd.unit(5) for details.
@
sign (e.g. name@string.service
): this means that they are instances of a template unit, whose actual file name does not contain the string
part (e.g. name@.service
). string
is called the instance identifier, and is similar to an argument that is passed to the template unit when called with the systemctl command: in the unit file it will substitute the %i
specifier. To be more accurate, before trying to instantiate the name@.suffix
template unit, systemd will actually look for a unit with the exact name@string.suffix
file name, although by convention such a "clash" happens rarely, i.e. most unit files containing an @
sign are meant to be templates. Also, if a template unit is called without an instance identifier, it will generally fail (except with certain systemctl commands, like cat
).The commands in the below table operate on system units since --system
is the implied default for systemctl. To instead operate on user units (for the calling user), use systemctl --user without root privileges. See also systemd/User#Basic setup to enable/disable user units for all users.
- Most commands also work if multiple units are specified, see systemctl(1) for more information.
- The
--now
switch can be used in conjunction withenable
,disable
, andmask
to respectively start, stop, or mask the unit immediately rather than after rebooting. - A package may offer units for different purposes. If you just installed a package,
pacman -Qql package | grep -Fe .service -e .socket
can be used to check and find them. - When available, enabling
unit.socket
instead ofunit.service
might be beneficial because the socket would start the service when necessary. See #Socket activation for more details.
Action | Command | Note |
---|---|---|
Analyzing the system state | ||
Show system status | systemctl status |
|
List running units | systemctl orsystemctl list-units |
|
List failed units | systemctl --failed |
|
List installed unit files1 | systemctl list-unit-files |
|
Show process status for a PID | systemctl status pid |
cgroup slice, memory and parent |
Checking the unit status | ||
Show a manual page associated with a unit | systemctl help unit |
as supported by the unit |
Status of a unit | systemctl status unit |
including whether it is running or not |
Check whether a unit is enabled | systemctl is-enabled unit |
|
Starting, restarting, reloading a unit | ||
Start a unit immediately | systemctl start unit as root |
|
Stop a unit immediately | systemctl stop unit as root |
|
Restart a unit | systemctl restart unit as root |
|
Reload a unit and its configuration | systemctl reload unit as root |
|
Reload systemd manager configuration2 | systemctl daemon-reload as root |
scan for new or changed units |
Enabling a unit | ||
Enable a unit to start automatically at boot | systemctl enable unit as root |
|
Enable a unit to start automatically at boot and start it immediately | systemctl enable --now unit as root |
|
Disable a unit to no longer start at boot | systemctl disable unit as root |
|
Reenable a unit3 | systemctl reenable unit as root |
i.e. disable and enable anew |
Masking a unit | ||
Mask a unit to make it impossible to start4 | systemctl mask unit as root |
|
Unmask a unit | systemctl unmask unit as root |
- See systemd.unit(5) § UNIT FILE LOAD PATH for the directories where available unit files can be found.
- This does not ask the changed units to reload their own configurations (see the Reload action).
- For example, in case its
[Install]
section has changed since last enabling it. - Both manually and as a dependency, which makes masking dangerous. Check for existing masked units with
$ systemctl list-unit-files --state=masked
Power management
polkit is necessary for power management as an unprivileged user. If you are in a local systemd-logind user session and no other session is active, the following commands will work without root privileges. If not (for example, because another user is logged into a tty), systemd will automatically ask you for the root password.
Action | Command |
---|---|
Shut down and reboot the system | systemctl reboot
|
Shut down and power-off the system | systemctl poweroff
|
Suspend the system | systemctl suspend
|
Put the system into hibernation (write RAM to disk) | systemctl hibernate
|
Put the system into hybrid-sleep state (also called suspend-to-both, it saves RAM to disk and then suspends) | systemctl hybrid-sleep
|
First suspend the system, then wake up after a configured time in order to just hibernate the system | systemctl suspend-then-hibernate
|
Perform a reboot of the userspace-only with a #Soft reboot. | systemctl soft-reboot
|
Soft reboot
Soft reboot is a special kind of a userspace-only reboot operation that does not involve the kernel. It is implemented by systemd-soft-reboot.service(8) and can be invoked through systemctl soft-reboot
. As with kexec, it skips firmware re-initialization, but additionally the system does not go through kernel initialization and initramfs, and unlocked dm-crypt devices remain attached.
When /run/nextroot/
contains a valid root file system hierarchy (e.g. is the root mount of another distribution or another snapshot), soft-reboot would switch the system root into it, allowing for switching to another installation without losing states managed by kernel, e.g. networking.
/run/nextroot/
is not necessarily a mount point or backed by physical device. For example, it can reside in the /run/
tmpfs. systemd will turn /run/nextroot/
automatically into a mount point on soft-reboot.systemctl soft-reboot
after package updates that involved the kernel and initramfs.Writing unit files
The syntax of systemd's unit files (systemd.unit(5)) is inspired by XDG Desktop Entry Specification .desktop files, which are in turn inspired by Microsoft Windows .ini files. Unit files are loaded from multiple locations (to see the full list, run systemctl show --property=UnitPath
), but the main ones are (listed from lowest to highest precedence)
/usr/lib/systemd/system/
: units provided by installed packages/etc/systemd/system/
: units installed by the system administrator
- The load paths are completely different when running systemd in user mode.
- systemd unit names may only contain ASCII alphanumeric characters, underscores and periods. All other characters must be replaced by C-style "\x2d" escapes, or employ their predefined semantics ('@', '-'). See systemd.unit(5) and systemd-escape(1) for more information.
Look at the units installed by your packages for examples, as well as systemd.service(5) § EXAMPLES.
#
may be used in unit-files as well, but only in new lines. Do not use end-line comments after systemd parameters or the unit will fail to activate.systemd-analyze(1) can help verifying the work. See the systemd-analyze verify FILE...
section of that page.
Handling dependencies
With systemd, dependencies can be resolved by designing the unit files correctly. The most typical case is when unit A requires 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.
Dependencies are typically placed on services and not on #Targets. For example, network.target
is pulled in by whatever service configures your network interfaces, therefore ordering your custom unit after it is sufficient since network.target
is started anyway.
Service types
There are several different start-up types to consider when writing a custom service file. This is set with the Type=
parameter in the [Service]
section
Type=simple
(default): systemd considers the service to be started up immediately. The process must not fork. Do not use this type if other services need to be ordered on this service, unless it is socket activated.Type=forking
: systemd considers the service started up once the process forks and the parent has exited. For classic daemons, use this type unless you know that it is not necessary. You should specifyPIDFile=
as well so systemd can keep track of the main process.Type=oneshot
: this is useful for scripts that do a single job and then exit. You may want to setRemainAfterExit=yes
as well so that systemd still considers the service as active after the process has exited. SettingRemainAfterExit=yes
is appropriate for the units which change the system state (e.g., mount some partition). See also [1] for the differences of simple and oneshot.Type=notify
: identical toType=simple
, but with the stipulation that the daemon will send a signal to systemd when it is ready. The reference implementation for this notification is provided by libsystemd-daemon.so.Type=dbus
: the service is considered ready when the specifiedBusName
appears on DBus's system bus.Type=idle
: systemd will delay execution of the service binary until all jobs are dispatched. Other than that behavior is very similar toType=simple
.
See the systemd.service(5) § OPTIONS man page for a more detailed explanation of the Type
values.
Editing provided units
To avoid conflicts with pacman, unit files provided by packages should not be directly edited. There are two safe ways to modify a unit without touching the original file: create a new unit file which overrides the original unit or create drop-in snippets which are applied on top of the original unit. For both methods, you must reload the unit afterwards to apply your changes. This can be done either by editing the unit with systemctl edit
(which reloads the unit automatically) or by reloading all units with
# systemctl daemon-reload
- You can use systemd-delta to see which unit files have been overridden or extended and what exactly has been changed.
- Use
systemctl cat unit
to view the content of a unit file and all associated drop-in snippets.
Replacement unit files
To replace the unit file /usr/lib/systemd/system/unit
, create the file /etc/systemd/system/unit
and reenable the unit to update the symlinks.
Alternatively, run
# systemctl edit --full unit
This opens /etc/systemd/system/unit
in your editor (copying the installed version if it does not exist yet) and automatically reloads it when you finish editing.
Drop-in files
To create drop-in files for the unit file /usr/lib/systemd/system/unit
, create the directory /etc/systemd/system/unit.d/
and place .conf files there to override or add new options. systemd will parse and apply these files on top of the original unit.
The easiest way to do this is to run
# systemctl edit unit --drop-in=drop_in_name
This opens the file /etc/systemd/system/unit.d/drop_in_name.conf
in your text editor (creating it if necessary) and automatically reloads the unit when you are done editing. Omitting --drop-in=
option will result in systemd using the default file name override.conf
.
- The key must be still placed in the appropriate section in the override file.
- Not all keys can be overridden with drop-in files. For example, for changing
Conflicts=
a replacement file is necessary. - You can use top-level drop-in files to affect all units of the same type. For example, a drop-in file in
/etc/systemd/system/service.d/
affects all .service units. You can see an example in #Notifying_about_failed_services
Revert to vendor version
To revert any changes to a unit made using systemctl edit
do
# systemctl revert unit
Examples
For example, if you simply want to add an additional dependency to a unit, you may create the following file
/etc/systemd/system/unit.d/customdependency.conf
[Unit] Requires=new dependency After=new dependency
As another example, in order to replace the ExecStart
directive, create the following file
/etc/systemd/system/unit.d/customexec.conf
[Service] ExecStart= ExecStart=new command
Note how ExecStart
must be cleared before being re-assigned [2]. The same holds for every item that can be specified multiple times, e.g. OnCalendar
for timers.
One more example to automatically restart a service
/etc/systemd/system/unit.d/restart.conf
[Service] Restart=always RestartSec=30
Service logging levels
For services that send logs directly to journald or syslog, you can control their verbosity by setting a numeric value between 0 and 6 for the LogLevelMax=
parameter in the [Service]
section using the methods described above. For example
/etc/systemd/system/unit.d/override.conf
[Service] LogLevelMax=3
The standard log levels are identical to those used to filter the journal. Setting a lower number excludes all higher and less important log messages from your journal.
Suppressing a service's standard output
If a service is echoing stdout and/or stderr output, by default this will end up in the journal as well. This behavior can be suppressed by setting StandardOutput=null
and/or StandardError=null
in the [Service]
section. Other values than null
can be used to further tweak this behavior. See systemd.exec(5) § LOGGING_AND_STANDARD_INPUT/OUTPUT.
Targets
systemd uses targets to group units together via dependencies and as standardized synchronization points. They serve a similar purpose as runlevels but act a little differently. Each target is named instead of numbered and is intended to serve a specific purpose with the possibility of having multiple ones active at the same time. Some targets are implemented by inheriting all of the services of another target and adding additional services to it. There are systemd targets that mimic the common SystemVinit runlevels.
Get current targets
The following should be used under systemd instead of running runlevel
$ systemctl list-units --type=target
Create custom target
The runlevels that held a defined meaning under sysvinit (i.e., 0, 1, 3, 5, and 6); have a 1:1 mapping with a specific systemd target. Unfortunately, there is no good way to do the same for the user-defined runlevels like 2 and 4. If you make use of those it is suggested that you make a new named systemd target as /etc/systemd/system/your target
that takes one of the existing runlevels as a base (you can look at /usr/lib/systemd/system/graphical.target
as an example), make a directory /etc/systemd/system/your target.wants
, and then symlink the additional services from /usr/lib/systemd/system/
that you wish to enable.
Mapping between SysV runlevels and systemd targets
SysV Runlevel | systemd Target | Notes |
---|---|---|
0 | poweroff.target | Halt the system. |
1, s, single | rescue.target | Single user mode. |
2, 4 | multi-user.target | User-defined/Site-specific runlevels. By default, identical to 3. |
3 | multi-user.target | Multi-user, non-graphical. Users can usually login via multiple consoles or via the network. |
5 | graphical.target | Multi-user, graphical. Usually has all the services of runlevel 3 plus a graphical login. |
6 | reboot.target | Reboot |
emergency | emergency.target | Emergency shell |
Change current target
In systemd, targets are exposed via target units. You can change them like this
# systemctl isolate graphical.target
This will only change the current target, and has no effect on the next boot. This is equivalent to commands such as telinit 3
or telinit 5
in Sysvinit.
Change default target to boot into
The standard target is default.target
, which is a symlink to graphical.target
. This roughly corresponds to the old runlevel 5.
To verify the current target with systemctl
$ systemctl get-default
To change the default target to boot into, change the default.target
symlink. With systemctl
# systemctl set-default multi-user.target
Removed /etc/systemd/system/default.target. Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.
Alternatively, append one of the following kernel parameters to your boot loader
systemd.unit=multi-user.target
(which roughly corresponds to the old runlevel 3),systemd.unit=rescue.target
(which roughly corresponds to the old runlevel 1).
Default target order
systemd chooses the default.target
according to the following order
- Kernel parameter shown above
- Symlink of
/etc/systemd/system/default.target
- Symlink of
/usr/lib/systemd/system/default.target
systemd components
Some (not exhaustive) components of systemd are
- kernel-install — to automatically move kernels and their respective initramfs images to the boot partition;
- systemd-analyze(1) — 可用于确定启动性能、统计信息和检索其他状态和跟踪信息,以及验证单元文件的正确性。它还用于访问对高级调试有用的特殊功能。
- systemd-boot — 简单的 UEFI 启动管理器;
- systemd-creds — 用于安全地存储和检索 systemd 单元使用的凭据;
- systemd-cryptenroll — 将 PKCS#11、FIDO2、TPM2 令牌/设备注册到 LUKS2 加密卷;
- systemd-firstboot — 首次启动前的基本系统设置初始化;
- systemd-homed — 便携式人类用户帐户;
- systemd-logind(8) — 会话管理;
- systemd-networkd — 网络配置管理;
- systemd-nspawn — 轻量级命名空间容器;
- systemd-repart — 创建分区表,添加或扩展分区;
- systemd-resolved — 网络域名解析;
- systemd-run(1) / run0(1) — 临时和交互式地获取提升的或不同的权限。
- systemd-stub(7) — 用于创建统一内核镜像的 UEFI 启动存根;
- systemd-sysusers(8) — 在软件包安装或启动时创建系统用户和组,并将用户添加到组;
- systemd-timesyncd — 跨网络的系统时间同步;
- systemd/Journal — 系统日志记录;
- systemd/Timers — 用于控制 .service 文件或事件的单调或实时定时器,是 cron 的合理替代方案。
systemd.mount - 挂载
systemd 负责挂载 /etc/fstab
中指定的分区和文件系统。systemd-fstab-generator(8) 将 /etc/fstab
中的所有条目转换为 systemd 单元;这在启动时以及系统管理器配置重新加载时执行。
systemd 扩展了通常的 fstab 功能,并提供了额外的挂载选项。这些选项会影响挂载单元的依赖关系。例如,它们可以确保仅在网络启动后或仅在另一个分区挂载后才执行挂载。systemd 特定的完整挂载选项列表,通常以 x-systemd.
为前缀,详见 systemd.mount(5) § FSTAB。
这些挂载选项的一个示例是自动挂载,这意味着仅在需要资源时才挂载,而不是在启动时自动挂载。这在 fstab#使用 systemd 自动挂载 中提供。
GPT 分区自动挂载
在 UEFI 启动的系统上,GPT 分区(如 root
、home
、swap
等)可以按照 可发现分区规范 自动挂载。因此,这些分区可以从 fstab 中省略,如果根分区是自动挂载的,则 root=
可以从内核命令行中省略。请参阅 systemd-gpt-auto-generator(8)。
先决条件是
- 当使用 mkinitcpio 时,需要 systemd hook。
- 所有自动挂载的分区必须与 ESP 位于同一物理磁盘上。
- 必须设置正确的 GPT 分区类型。请参阅 分区#分区方案。
- 引导加载程序必须设置 LoaderDevicePartUUID EFI 变量,以便可以识别使用的 EFI 系统分区。 systemd-boot、systemd-stub(7)、GRUB(使用 grub-mkconfig 生成的
grub.cfg
;自定义grub.cfg
需要 加载 bli 模块)和 rEFInd(默认情况下未启用) 支持此功能。可以通过运行bootctl
并检查Boot loader sets ESP information
的状态,或者在使用统一内核镜像 启动时检查Stub sets ESP information
的状态来验证这一点。
udev 将创建一个指向根卷块设备的 /dev/gpt-auto-root
符号链接。如果根分区使用 LUKS 加密,/dev/gpt-auto-root
将指向解锁/映射的卷,而 /dev/gpt-auto-root-luks
将指向加密的分区。
/var
为了使 /var
自动挂载工作,PARTUUID 必须与由机器 ID 键控的分区类型 UUID 的 SHA256 HMAC 哈希匹配。所需的 PARTUUID 可以使用以下命令获得
$ systemd-id128 -u var-partition-uuid
/etc/machine-id
读取机器 ID,这使得在系统安装之前不可能知道所需的 PARTUUID。systemd-sysvcompat
systemd-sysvcompat(base 要求)的主要作用是提供传统的 linux init 二进制文件。对于 systemd 控制的系统,init
只是其 systemd
可执行文件的符号链接。
此外,它还提供了 SysVinit 用户可能习惯的四个便捷快捷方式。便捷快捷方式为 halt(8)、poweroff(8)、reboot(8) 和 shutdown(8)。这四个命令中的每一个都是 systemctl
的符号链接,并受 systemd 行为的约束。因此,#电源管理 中的讨论适用。
systemd-based 系统可以通过使用 init=
启动参数(例如,参见 /bin/init is in systemd-sysvcompat ?)和 systemd 原生 systemctl
命令参数来放弃这些 System V 兼容性方法。
systemd-tmpfiles - 临时文件
systemd-tmpfiles 创建、删除和清理易失性和临时文件和目录。它读取 /etc/tmpfiles.d/
和 /usr/lib/tmpfiles.d/
中的配置文件,以发现要执行的操作。前一个目录中的配置文件优先于后一个目录中的配置文件。
配置文件通常与服务文件一起提供,它们的命名风格为 /usr/lib/tmpfiles.d/program.conf
。例如,Samba 守护程序期望目录 /run/samba
存在并具有正确的权限。因此,samba 软件包附带此配置
/usr/lib/tmpfiles.d/samba.conf
D /run/samba 0755 root root
配置文件也可用于在启动时将值写入某些文件。例如,如果您使用 /etc/rc.local
通过 echo USBE > /proc/acpi/wakeup
禁用 USB 设备唤醒,则可以使用以下 tmpfile 代替
/etc/tmpfiles.d/disable-usb-wake.conf
# Path Mode UID GID Age Argument w /proc/acpi/wakeup - - - - USBE
可以将多行写入同一文件,可以使用参数中的 \n
或在多行(包括第一行)上使用 w+
类型进行追加
/etc/tmpfiles.d/disable-usb-wake.conf
# Path Mode UID GID Age Argument w+ /proc/acpi/wakeup - - - - USBE w+ /proc/acpi/wakeup - - - - LID0
有关详细信息,请参阅 systemd-tmpfiles(8) 和 tmpfiles.d(5) 手册页。
/sys
中的选项,因为 systemd-tmpfiles-setup 服务可能在加载相应的设备模块之前运行。在这种情况下,您可以检查模块是否具有要使用 modinfo module
设置的选项的参数,并使用 /etc/modprobe.d 中的配置文件 设置此选项。否则,您将必须编写一个 udev 规则 以在设备出现时立即设置相应的属性。
Drop-in 配置文件
不应直接编辑软件包提供的配置文件,以避免与 pacman 更新冲突。为此,许多(但不是全部)systemd 软件包提供了一种修改配置的方法,但无需通过创建 drop-in 代码段来触及原始文件。检查软件包手册以查看是否支持 drop-in 配置文件。
要为单元文件 /etc/systemd/unit.conf
创建 drop-in 配置文件,请创建目录 /etc/systemd/unit.conf.d/
并将 .conf 文件放在此处以覆盖或添加新选项。 systemd 将解析这些文件并将它们应用在原始单元之上。
检查整体配置
$ systemd-analyze cat-config systemd/unit.conf
应用的 drop-in 代码段文件和内容将列在末尾。 重启 服务以使更改生效。
技巧和窍门
套接字激活
某些软件包提供 .socket 单元。例如,cups 提供了一个 cups.socket
单元[3]。如果 cups.socket
被启用(并且 cups.service
保持禁用状态),systemd 将不会立即启动 CUPS;它只会监听相应的套接字。然后,每当程序尝试连接到这些 CUPS 套接字之一时,systemd 将启动 cups.service
并透明地将这些端口的控制权移交给 CUPS 进程。
GUI 配置工具
- systemadm — systemd 单元的图形浏览器。它可以显示单元列表,可以按类型过滤。
- SystemdGenie — 基于 KDE 技术的 systemd 管理实用程序。
在网络启动后运行服务
要延迟服务直到网络启动后,请在 .service 文件中包含以下依赖项
/etc/systemd/system/foo.service
[Unit] ... Wants=network-online.target After=network-online.target ...
还必须启用正在使用的 网络管理器 的网络等待服务,以便 network-online.target
正确反映网络状态。
- 如果使用 NetworkManager,则应将
NetworkManager-wait-online.service
与NetworkManager.service
一起启用。使用systemctl is-enabled NetworkManager-wait-online.service
检查是否是这种情况。如果未启用,则重新启用NetworkManager.service
。 - 对于 netctl,启用
netctl-wait-online.service
(除非您正在使用 netctl-auto;请参阅 FS#75836)。 - 如果使用 systemd-networkd,则应将
systemd-networkd-wait-online.service
与systemd-networkd.service
一起启用。使用systemctl is-enabled systemd-networkd-wait-online.service
检查是否是这种情况。如果未启用,则重新启用systemd-networkd.service
。
有关更详细的说明,请参阅 网络配置同步点 中的讨论。
如果服务需要执行 DNS 查询,则还应将其排序在 nss-lookup.target
之后
/etc/systemd/system/foo.service
[Unit] ... Wants=network-online.target After=network-online.target nss-lookup.target ...
请参阅 systemd.special(7) § 特殊被动系统单元。
为了使 nss-lookup.target
产生任何效果,它需要一个通过 Wants=nss-lookup.target
拉入它并在它之前用 Before=nss-lookup.target
排序的服务。通常,这是由本地 DNS 解析器 完成的。
使用以下命令检查哪个活动服务(如果有)正在拉入 nss-lookup.target
$ systemctl list-dependencies --reverse nss-lookup.target
默认启用已安装的单元
Arch Linux 附带 /usr/lib/systemd/system-preset/99-default.preset
,其中包含 disable *
。这会导致 systemctl preset 默认禁用所有单元,这样当安装新软件包时,用户必须手动启用该单元。
如果不希望这样做,只需从 /etc/systemd/system-preset/99-default.preset
创建一个符号链接到 /dev/null
,以便覆盖配置文件。这将导致 systemctl preset 启用所有已安装的单元(无论单元类型如何),除非在 systemctl preset 的配置目录中的另一个文件中指定。用户单元不受影响。有关更多信息,请参阅 systemd.preset(5)。
沙盒化应用程序环境
可以创建一个单元文件作为沙箱,以在强化的虚拟环境中隔离应用程序及其进程。 systemd 利用 命名空间、允许/拒绝的 capabilities 列表和 控制组,通过广泛的执行环境配置来容器化进程— systemd.exec(5)。
增强具有应用程序沙箱功能的现有 systemd 单元文件通常需要试错测试,并慷慨地使用 strace、stderr 和 journalctl(1) 错误日志记录和输出工具。您可能需要首先搜索上游文档以查找已完成的测试,以作为试验的基础。要获得可能的强化选项的起点,请运行
$ systemd-analyze security unit
一些关于如何使用 systemd 部署沙箱的示例
CapabilityBoundingSet
定义了 capabilities(7) 的列表,这些 capabilities 允许或拒绝单元。请参阅 systemd.exec(5) § CAPABILITIES。- 例如,
CAP_SYS_ADM
capability 应该是 安全沙箱的目标之一:CapabilityBoundingSet=~ CAP_SYS_ADM
- 例如,
通知有关失败的服务
为了通知有关服务失败,需要在相应的服务文件中添加 OnFailure=
指令,例如使用 drop-in 配置文件。可以使用顶级 drop-in 配置文件将此指令添加到每个服务单元。有关顶级 drop-in 的详细信息,请参阅 systemd.unit(5)。
为服务创建顶级 drop-in
/etc/systemd/system/service.d/toplevel-override.conf
[Unit] OnFailure=failure-notification@%n.service
这将 OnFailure=failure-notification@%n.service
添加到每个服务文件。如果 some_service_unit 失败,将启动 failure-notification@some_service_unit.service
以处理通知传递(或配置为执行的任何任务)。
创建 failure-notification@.service
模板单元
/etc/systemd/system/failure-notification@.service
[Unit] Description=Send a notification about a failed systemd unit [Service] Type=oneshot ExecStart=/path/to/failure-notification.sh %i # runs as a temporary user/group and enables several other security precautions DynamicUser=true
您可以创建 failure-notification.sh
脚本并定义要执行的操作或如何通知。示例包括发送电子邮件、显示桌面通知、使用 gotify、XMPP 等。 %i
将是失败的服务单元的名称,并将作为参数传递给脚本。
为了防止在启动失败时再次一次又一次地启动 failure-notification@.service
实例的递归,请创建一个与顶级 drop-in 同名的空 drop-in 配置文件(空的 service-level drop-in 配置文件优先于顶级 drop-in 并覆盖后者)
# mkdir -p /etc/systemd/system/failure-notification@.service.d # touch /etc/systemd/system/failure-notification@.service.d/toplevel-override.conf
通过电子邮件通知
您可以设置 systemd 在单元失败时发送电子邮件。如果作业输出到 stdout 或 stderr,Cron 会将邮件发送到 MAILTO
,但许多作业设置为仅在出错时输出。首先,您需要两个文件:一个用于发送邮件的可执行文件和一个用于启动可执行文件的 .service 文件。对于此示例,可执行文件只是一个使用 sendmail
的 shell 脚本,该脚本位于提供 smtp-forwarder
的软件包中。
/usr/local/bin/systemd-email
#!/bin/sh /usr/bin/sendmail -t <<ERRMAIL To: $1 From: systemd <root@$HOSTNAME> Subject: $2 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 $(systemctl status --full "$2") ERRMAIL
无论您使用什么可执行文件,它都可能应该至少接受两个参数,就像这个 shell 脚本一样:要发送到的地址和要获取状态的单元文件。我们创建的 .service 将传递这些参数
/etc/systemd/system/status_email_user@.service
[Unit] Description=status email for %i to user [Service] Type=oneshot ExecStart=/usr/local/bin/systemd-email address %i User=nobody Group=systemd-journal
其中 user
是被电子邮件的用户,address
是该用户的电子邮件地址。虽然收件人是硬编码的,但要报告的单元文件作为实例参数传递,因此这项服务可以为许多其他单元发送电子邮件。此时,您可以 启动 status_email_user@dbus.service
以验证您是否可以收到电子邮件。
然后只需编辑您想要接收电子邮件的服务,并将 OnFailure=status_email_user@%n.service
添加到 [Unit]
部分。 %n
将单元的名称传递给模板。
- 如果您按照 sSMTP#安全 设置了 sSMTP 安全性,则用户
nobody
将无权访问/etc/ssmtp/ssmtp.conf
,并且systemctl start status_email_user@dbus.service
命令将失败。一种解决方案是在status_email_user@.service
单元中使用root
作为 User。 - 如果您尝试在电子邮件脚本中使用
mail -s somelogs address
,mail
将 fork,并且当 systemd 看到您的脚本退出时,它将杀死 mail 进程。通过执行mail -Ssendwait -s somelogs address
使邮件不 fork。
DynamicUser=true
作为 User=nobody
的替代品,现在不鼓励使用 User=nobody
。有关更多详细信息,请参阅 GitHub issue 428。在关机时自动关闭外部 HDD
故障排除
调查失败的服务
要查找未能启动的 systemd 服务
$ systemctl --state=failed
要找出它们失败的原因,请检查它们的日志输出。有关详细信息,请参阅 systemd/Journal#过滤输出。
诊断启动问题
systemd 具有用于诊断启动过程问题的几个选项。有关更通用的说明和在 systemd 接管启动过程之前捕获启动消息的选项,请参阅 启动调试。另请参阅 systemd 调试文档。
诊断服务
如果某些 systemd 服务行为异常,或者您想获得有关正在发生的事情的更多信息,请将 SYSTEMD_LOG_LEVEL
环境变量 设置为 debug
。例如,要在调试模式下运行 systemd-networkd 守护程序
为服务添加一个 drop-in 文件,添加以下两行
[Service] Environment=SYSTEMD_LOG_LEVEL=debug
或者,等效地,手动设置环境变量
# SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd
然后重启 systemd-networkd 并使用 -f
/--follow
选项监视服务的日志。
关机/重启时间过长
如果关机过程花费很长时间(或似乎冻结),则很可能是某个服务未退出造成的。 systemd 会等待一段时间让每个服务退出,然后再尝试杀死它。要找出您是否受到影响,请参阅 systemd 文档中的 关机最终完成。
常见问题是关机或挂起过程停滞。要验证是否是这种情况,您可以运行以下任一命令并检查输出
# systemctl poweroff
Failed to power off system via logind: There's already a shutdown or sleep operation in progress
# systemctl list-jobs
JOB UNIT TYPE STATE ... 21593 systemd-suspend.service start running 21592 suspend.target start waiting ..
解决方案 是通过运行以下命令取消这些作业
# systemctl cancel # systemctl stop systemd-suspend.service
然后再次尝试关机或重启。
短时进程似乎没有记录任何输出
如果以 root 身份运行 journalctl -u foounit
没有显示任何短时服务的输出,请查看 PID。例如,如果 systemd-modules-load.service
失败,并且 systemctl status systemd-modules-load
显示它作为 PID 123 运行,那么您可能能够在日志中看到该 PID 的输出,即以 root 身份运行 journalctl -b _PID=123
。日志的元数据字段(如 _SYSTEMD_UNIT
和 _COMM
)是异步收集的,并且依赖于 /proc
目录来查找进程是否存在。修复此问题需要修复内核以通过套接字连接提供此数据,类似于 SCM_CREDENTIALS
。简而言之,这是一个 错误。请记住,根据 systemd 的设计,立即失败的服务可能不会向日志输出任何内容。
启动时间随时间增加
在使用 systemd-analyze
后,许多用户注意到他们的启动时间与以前相比显着增加。在使用 systemd-analyze blame
后,NetworkManager 被报告为花费异常长的时间才能启动。
一些用户的问题是由于 /var/log/journal
变得太大。这可能会对性能产生其他影响,例如 systemctl status
或 journalctl
。因此,解决方案是删除文件夹中的每个文件(理想情况下,至少暂时备份到某个地方),然后按照 Systemd/Journal#日志大小限制 中所述设置日志文件大小限制。
systemd-tmpfiles-setup.service 启动时失败
从 systemd 219 开始,/usr/lib/tmpfiles.d/systemd.conf
为 /var/log/journal
下的目录指定 ACL 属性,因此,需要为日志所在的文件系统启用 ACL 支持。
有关如何在托管 /var/log/journal
的文件系统上启用 ACL 的说明,请参阅 访问控制列表#启用 ACL。
禁用远程计算机上的紧急模式
您可能希望禁用远程计算机上的紧急模式,例如,Azure 或 Google Cloud 上托管的虚拟机。这是因为如果触发紧急模式,计算机将无法连接到网络。
要禁用它,请屏蔽 emergency.service
和 emergency.target
。
错误“Unit xxx.service not found”,但服务确实存在
您可能正在尝试将用户单元作为系统单元启动或启用。 systemd.unit(5) 指示哪些单元位于何处。默认情况下,systemctl 对系统服务进行操作。
有关更多详细信息,请参阅 Systemd/User。
另请参阅
- Wikipedia:systemd
- 官方网站
- systemd(1)
- 其他发行版
- Lennart 的博客故事, 更新 1, 更新 2, 更新 3, 摘要
- 调试 Systemd 服务
- 面向管理员的 systemd (PDF)
- 如何使用 Systemctl 管理 Systemd 服务和单元
- 使用 systemd-logind 进行会话管理
- Systemd 文件的 Emacs 语法高亮
- 两部分 The H Open 杂志的介绍性文章。