如何覆盖或配置systemd服务?


109

许多sysv初始化脚本都使用相应的文件/etc/default来允许管理员配置它。可以使用.override文件来修改新贵作业。现在,systemd是Ubuntu中的默认设置,我该如何覆盖或配置systemd单位?


请注意,清除ExecStart=带有空白条目的时,您不能在其后添加注释,例如:ExecStart= # Empty line to clear previous entries.这将被视为另一个ExecStart=条目并添加到列表中。PS。由于我的声誉低下,我无法在评论中添加评论。
tysik

Answers:


185

systemd单位不必遵守中的文件/etc/defaultsystemd可以轻松配置,但是要求您了解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

这样会在/etc/systemd/system以该单位命名的目录中创建一个目录,并override.conf在该目录(/etc/systemd/system/foo.service.d/override.conf)中创建一个文件。您可以使用此文件(或中的其他.conf文件/etc/systemd/system/foo.service.d/)添加或覆盖设置。

覆盖命令参数

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

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

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

要覆盖此内容,请执行以下操作:

sudo systemctl edit getty@tty2

并添加:

[Service]
ExecStart=
ExecStart=-/sbin/agetty -a muru --noclear %I $TERM

注意:

  1. 我必须ExecStart在再次设置之前明确清除,因为它是一个加性设置,类似于AfterEnvironment(作为一个整体,而不是每个变量)和EnvironmentFile,并且与诸如RestartSec或的替代设置相反TypeExecStart只能有多个条目用于Type=oneshot服务。
  2. 我必须使用适当的节头。在原始文件ExecStart中的[Service]部分中,因此我的替代项也必须放在ExecStart[Service]部分中。通常,查看使用的实际服务文件systemctl cat会告诉您需要覆盖的内容以及该文件所在的部分。

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

sudo systemctl daemon-reload

但是,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 ; ... }

如果我这样做:

sudo systemctl restart getty@tty2

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

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

systemctl edit getty@

超越环境

/etc/default文件的一个常见用例是设置环境变量。通常,它/etc/default是一个Shell脚本,因此您可以在其中使用Shell语言构造。systemd但是,使用,情况并非如此。您可以通过两种方式指定环境变量:

通过文件

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

$ cat /path/to/some/file
FOO=bar

然后,您可以添加到替代:

[Service]
EnvironmentFile=/path/to/some/file

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

通过Environment条目

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

[Service]
Environment=FOO=bar

但是,使用多个变量,空格等可能会变得棘手。请查看我的其他答案之一,以了解此类实例。

进一步阅读

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

以下链接将很有用:


1
在为非oneshot类型的服务设置变量之前,必须清除该变量。这解决了我的问题。
科林

3
systemd.service(5)联机帮助页上的@MarkEdington ,有关以下内容ExecStart:“除非Type =是oneshot,否则必须给出一个命令。当使用Type = oneshot时,可以指定零个或多个命令。可以通过在同一行中提供多个命令行来指定命令指令,或者可以重复指定此指令,但效果相同。如果将空字符串分配给此选项,则将重新启动要启动的命令列表,该选项的先前分配将无效。”
muru

1
@Orient你可以sudo rm覆写文件,然后systemctl daemon-reload,也可以systemctl edit在与评论替代取代一切。服务文件中的注释以开头#
muru

3
@Orientsystemctl revert foo
Ayell

1
这三种方法(覆盖文件,环境文件,环境变量)的优先顺序是什么?即,对于在所有三个变量中定义的变量,哪个值将是有效的?
Nikolaos Kakouros
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.