许多 sysv init 脚本使用相应的文件来/etc/default
允许管理员对其进行配置。可以使用.override
文件修改 Upstart 作业。既然 systemd 现在是 Ubuntu 中的默认设置,我该如何覆盖或配置 systemd 单元?
答案1
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
这将创建一个以/etc/systemd/system
单位名称命名的目录,并override.conf
在该目录中创建一个文件(/etc/systemd/system/foo.service.d/override.conf
)。您可以使用此文件(或.conf
中的其他文件/etc/systemd/system/foo.service.d/
)添加或覆盖设置。这也适用于非服务单位 - 您可以执行systemctl edit foo.mount
、等。如果您未指定类型,systemctl edit foo.timer
它将假定为默认类型。.service
覆盖命令参数
以getty
服务为例。假设我想让 TTY2 自动登录到我的用户(这不是明智之举,只是举个例子)。TTY2 由服务运行getty@tty2
(tty2
作为模板的一个实例)。为此,我必须修改服务。/lib/systemd/system/[email protected]
getty@tty2
$ systemctl cat getty@tty2
# /lib/systemd/system/[email protected]
# 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 [email protected], 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
注意:
在再次设置之前,我必须明确清除
ExecStart
它,因为它是一个附加设置,类似于其他列表Environment
(作为一个整体,而不是每个变量)和EnvironmentFile
;与覆盖设置(如RestartSec
或)不同Type
。如果我没有清除它,systemd 将执行每一ExecStart
行,但您只能为服务设置多个ExecStart
条目。Type=oneshot
- 依赖项设置(如
Before
、After
、Wants
等)也是列表,但无法使用此方法清除。您必须为此覆盖/替换整个服务(见下文)。
- 依赖项设置(如
我必须使用正确的节标题。在原始文件中,
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/foo
仅包含作业而不包含 shell 语法,则可以将其用作EnvironmentFile
。
通过Environment
条目
上述操作也可以使用以下覆盖来实现:
[Service]
Environment=FOO=bar
但是,如果存在多个变量、空格等,这可能会变得很棘手。看看我的另一个答案作为此类实例的一个例子。
编辑变化
完全替换现有设备
如果您想要对现有单元进行大规模更改,以便有效地将其完全替换,那么您可以这样做:
systemctl edit --full foo
临时编辑
在 systemd 文件层次结构中,/etc
优先于/run
,而 又优先于/lib
。到目前为止所说的所有内容也适用于使用/run/systemd/system
而不是/etc/systemd/system
。通常/run
是一个临时文件系统,其内容在重启时会丢失,因此如果您只想在重启之前覆盖一个单元,您可以执行以下操作:
systemctl edit --runtime foo
但是,您不能使用此方法临时覆盖已存在的内容/etc
(例如,快照服务文件通常直接在中创建/etc/systemd/system
,因此您只能使用中的文件覆盖它们/etc/system/system/<snap-service-name>.service.d
)。
覆盖用户单位
到目前为止所说的所有内容也适用于用户单元,使用systemctl --user edit
、systemctl --user daemon-reload
等代替相应的系统单元命令。覆盖文件转到~/.config/systemd/user
而不是/etc/systemd/system
。如果您作为管理员想要覆盖所有用户的用户单元,则使用/etc/systemd/user
代替。
设置特定属性
许多资源控制属性可以直接使用命令进行设置systemctl set-property
。手册页中的示例:
systemctl set-property foobar.service CPUWeight=200 MemoryMax=2G IPAccounting=yes
更改会立即应用,并会持久保存以覆盖文件。例如,以下命令将立即更新服务的资源配置:
systemctl --user set-property foobar.service CPUWeight=200 MemoryMax=2G
并且在用户的主目录中添加以下文件(因为--user
使其成为用户单元):
% head .config/systemd/user.control/cann.service.d/50-*
==> .config/systemd/user.control/cann.service.d/50-CPUWeight.conf <==
# This is a drop-in unit file extension, created via "systemctl set-property"
# or an equivalent operation. Do not edit.
[Service]
CPUWeight=200
==> .config/systemd/user.control/cann.service.d/50-MemoryMax.conf <==
# This is a drop-in unit file extension, created via "systemctl set-property"
# or an equivalent operation. Do not edit.
[Service]
MemoryMax=2147483648
撤消更改
您可以简单地删除相应的覆盖文件,然后让systemctl daemon-reload
systemd 读取更新的单元定义。
你也可以恢复所有更改(包括来自的更改systemctl set-property
):
systemctl revert foo
进一步阅读
通过这种机制,可以非常轻松地覆盖systemd
单位,以及撤消此类更改(只需删除覆盖文件即可)。这些并不是唯一可以修改的设置。
以下链接很有用:
- Arch Wiki 条目
systemd
- 管理员使用 systemd,第九部分:关于 /etc/sysconfig 和 /etc/default(由 systemd 的首席开发人员 Lennart Poettering 撰写)
- 手册
systemd
页,特别是systemd.unit
和systemd.service
- Ubuntu Wiki 条目适用于 Upstart 用户的 Systemd