如何覆盖或配置 systemd 服务?

mur*_*uru 152 configuration services systemd

许多 sysv init 脚本使用相应的文件/etc/default来允许管理员对其进行配置。可以使用.override文件修改新贵的工作。既然 systemd 是 Ubuntu 中的默认设置,我该如何覆盖或配置 systemd 单元?

mur*_*uru 265

systemd单位不需要遵守/etc/default. systemd易于配置,但需要您了解 systemd 单元文件的语法。

包通常以/lib/systemd/system/. 这些是不可编辑的。相反,systemd允许您通过在/etc/systemd/system/.

对于给定的服务foo,该软件包将提供/lib/systemd/system/foo.service. 您可以使用 来检查其状态systemctl status foo,或使用 来查看其日志journalctl -u foo。要覆盖 的定义中的某些内容foo,请执行以下操作:

sudo systemctl edit foo
Run Code Online (Sandbox Code Playgroud)

这将创建一个/etc/systemd/system以单元命名的目录,并override.conf在该目录中创建一个文件 ( /etc/systemd/system/foo.service.d/override.conf)。您可以使用此文件(或 中的其他.conf文件/etc/systemd/system/foo.service.d/)添加或覆盖设置。这也适用于非服务单位-你可以这样做systemctl edit foo.mountsystemctl edit foo.timer等等。

覆盖命令参数

getty服务为例。假设我想让我的用户自动登录 TTY2(这不是可取的,只是一个例子)。TTY2 由getty@tty2服务运行(tty2作为模板的一个实例/lib/systemd/system/getty@service)。为此,我必须修改getty@tty2服务。

$ systemctl cat getty@tty2
# /lib/systemd/system/getty@.service
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
After=systemd-user-sessions.service plymouth-quit-wait.service
After=rc-local.service

# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes

# On systems without virtual consoles, don't start any getty. Note
# that serial gettys are covered by serial-getty@.service, not this
# unit.
ConditionPathExists=/dev/tty0

[Service]
# the VT is cleared by TTYVTDisallocate
ExecStart=-/sbin/agetty --noclear %I $TERM
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes

# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=

[Install]
WantedBy=getty.target
DefaultInstance=tty1
Run Code Online (Sandbox Code Playgroud)

特别是,我必须更改ExecStart当前的行:

$ systemctl cat getty@tty2 | grep Exec     
ExecStart=-/sbin/agetty --noclear %I $TERM
Run Code Online (Sandbox Code Playgroud)

要覆盖它,请执行以下操作:

sudo systemctl edit getty@tty2
Run Code Online (Sandbox Code Playgroud)

并添加:

[Service]
ExecStart=
ExecStart=-/sbin/agetty -a muru --noclear %I $TERM
Run Code Online (Sandbox Code Playgroud)

注意:

  1. 我必须ExecStart在再次设置之前明确清除,因为它是一个附加设置,类似于After, Environment(作为一个整体,而不是每个变量)和EnvironmentFile,并且反对像RestartSecor这样的覆盖设置TypeExecStart只能为Type=oneshot服务有多个条目。
  2. 我必须使用正确的节标题。在原始文件中,ExecStart位于该[Service]部分中,因此我的覆盖也必须放在ExecStart[Service]部分中。通常,查看实际使用的服务文件systemctl cat会告诉您需要覆盖的内容以及它位于哪个部分。

通常,如果您编辑 systemd 单元文件,要使其生效,您需要运行:

sudo systemctl daemon-reload
Run Code Online (Sandbox Code Playgroud)

但是,会systemctl edit自动为您执行此操作。

现在:

$ systemctl cat getty@tty2 | grep Exec
ExecStart=-/sbin/agetty --noclear %I $TERM
ExecStart=
ExecStart=-/sbin/agetty -a muru --noclear %I $TERM

$ systemctl show getty@tty2 | grep ExecS
ExecStart={ path=/sbin/agetty ; argv[]=/sbin/agetty -a muru --noclear %I $TERM ; ... }
Run Code Online (Sandbox Code Playgroud)

如果我这样做:

sudo systemctl restart getty@tty2
Run Code Online (Sandbox Code Playgroud)

然后按CtrlAltF2,快点!我将在该 TTY 上登录我的帐户。

正如我之前所说,getty@tty2是模板的一个实例。那么,如果我想覆盖该模板的所有实例怎么办?这可以通过编辑模板本身来完成(删除实例标识符 - 在这种情况下tty2):

systemctl edit getty@
Run Code Online (Sandbox Code Playgroud)

覆盖环境

/etc/default文件的一个常见用例是设置环境变量。通常,/etc/default是一个 shell 脚本,因此您可以在其中使用 shell 语言结构。随着systemd,然而,这并非如此。您可以通过两种方式指定环境变量:

通过文件

假设您已在文件中设置环境变量:

$ cat /path/to/some/file
FOO=bar
Run Code Online (Sandbox Code Playgroud)

然后,您可以添加到覆盖:

[Service]
EnvironmentFile=/path/to/some/file
Run Code Online (Sandbox Code Playgroud)

特别是,如果您/etc/default/grub只包含赋值而不包含 shell 语法,则可以将其用作EnvironmentFile.

通过Environment条目

也可以使用以下覆盖来完成上述操作:

[Service]
Environment=FOO=bar
Run Code Online (Sandbox Code Playgroud)

但是,对于多个变量、空格等,这可能会变得棘手。有关此类实例的示例,请查看我的其他答案之一

编辑的变化

完全更换现有单元

如果您想对现有单元进行大量更改,以便有效地完全替换它,您可以这样做:

systemctl edit --full foo
Run Code Online (Sandbox Code Playgroud)

临时编辑

在 systemd 文件层次结构中,/run优先于/etc,而后者又优先于/lib. 到目前为止所说的一切也适用于使用/run/systemd/system而不是/etc/systemd/system. 通常/run是一个临时文件系统,其内容在重新启动时丢失,因此如果您只想在重新启动之前覆盖一个单元,您可以执行以下操作:

systemctl edit --runtime foo
Run Code Online (Sandbox Code Playgroud)

撤消更改

您可以简单地删除相应的覆盖文件,然后systemctl daemon-reload让 systemd 读取更新的单元定义。

您还可以还原所有更改:

systemctl revert foo
Run Code Online (Sandbox Code Playgroud)

进一步阅读

通过这种机制,可以很容易地覆盖systemd单位,以及撤消此类更改(通过简单地删除覆盖文件)。这些不是唯一可以修改的设置。

以下链接会很有用:

  • @Orient `systemctl revert foo` (7认同)
  • 在为非 oneshot 类型的服务设置变量之前,您必须清除该变量。这解决了我的问题。 (3认同)
  • @MarkEdington 来自`systemd.service(5)` 联机帮助页,`ExecStart` 部分:“除非 Type= 是 oneshot,否则必须给出一个命令。当使用 Type=oneshot 时,可以指定零个或多个命令。命令可以通过在同一个指令中提供多个命令行来指定,或者,可以多次指定该指令,具有相同的效果。如果将空字符串分配给此选项,则要启动的命令列表将重置,优先分配此选项将无效。” (3认同)
  • @xenoterracide 取决于您是否要替换以前的值或只是添加另一个要执行的命令。 (3认同)
  • 很好的答案,除了一部分 - 它让你相信你可以重置“After”,基于“我必须在再次设置它之前显式清除 ExecStart,因为它是一个附加设置,类似于 After...”虽然它**是**一个列表/附加设置 - 正如我必须从[其他地方](https://unix.stackexchange.com/a/468067/395448)找到的那样 - 你**不能**重置依赖类型设置。 .. (3认同)
  • @Orient,您可以“sudo rm”覆盖文件,然后“systemctl daemon-reload”,或者您可以“systemctl edit”并用注释替换覆盖中的所有内容。服务文件中的注释以“#”开头。 (2认同)
  • 三种方法(覆盖文件、环境文件、环境变量)的优先顺序是什么?即,对于在所有三个中定义的变量,哪个值将是有效的? (2认同)