Systemd

Systemd基础

Unit管理

systemd管理和作用的基本对象是一个"Unit”,其中最常见的就是“service”(.service结尾的unit文件)。主要的管理工具就是systemctl,下面以nginx.service 为例:

1
2
3
4
sudo systemctl start nginx.service #启动服务
sudo systemctl stop nginx.service #停止服务
sudo systemctl restart nginx.service #重启服务
sudo systemctl reload nginx.service #不打断服务的情况下重新加载配置文件

启用与禁用Unit

默认情况下,大多数systemd单元文件不会在启动时自动启动。

1
2
sudo systemctl enable nginx.service  #开机启动服务
sudo systemctl disable nginx.service  #取消开机启动

系统状态概览

获取systemd列为“active”的unit文件

1
systemctl list-units

使用–all列出全部systemd试图加载或已经加载到内存中到unit文件

1
systemctl list-units --all

列出全部系统已安装到unit,包括那些systemd没去加载的

1
systemctl list-unit-files

查看日志信息

查看全部日志,从最早的开始:

1
journalctl

如果journald配置了保存先前的启动记录也会一并显示,有些发行版默认禁用此功能,可以编辑/etc/systemd/journald.conf文件,设置Storage=选项为"persistent”,也可以创建保存目录sudo mkdir -p /var/log/journal

如果只想看本次启动相关的内容,可以加上-b选项:

1
journalctl -b

只看kernel信息,加上-k选项:

1
journalctl -k

也可以组合起来,只看本次的kernel信息:

1
journalctl -k -b

查询Unit状态和日志

查看一个unit当前状态概览,包括是否活跃、进程信息和最新的日记账:

1
systemctl status nginx.service

只看相关unit的日记账,使用-u选项指定其名称:

1
journalctl -u nginx.service

同样可以限制本次启动:

1
journalctl -b -u nginx.service

检查unit和unit文件

unit文件中包含了systemd用于管理和运行unit的参数,查看unit文件完整内容:

1
systemctl cat nginx.service

查看unit依赖树,会递归展开依赖的unit:

1
systemctl list-dependencies nginx.service

展开全部依赖的unit:

1
systemctl list-dependencies --all nginx.service

查看systemd管理每个参数的值:

1
systemctl show nginx.service

修改Unit文件

添加一个unit片段文件,以增加或覆盖默认设置:

1
sudo systemctl edit nginx.service

修改unit文件的全部内容,而非片段:

1
sudo systemctl edit --full nginx.service

修改完成后,需承载systemd进程以生效:

1
sudo systemctl daemon-reload

Target(运行级别)

查看系统可用target:

1
systemctl list-unit-files --type=target

查看systemd启动时默认target:

1
systemctl get-default

更改默认target:

1
sudo systemctl set-default multi-user.target

查看target绑定的unit:

1
systemctl list-dependencies multi-user.target

使用isolate切换系统target,并停止所有非指定target绑定的unit,请确保关键服务不会被停止:

1
sudo systemctl isolate multi-user.target

停止与重启服务器

1
2
3
4
5
6
7
8
# 关闭系统
sudo systemctl halt
# 关机
sudo systemctl poweroff
# 重启
sudo systemctl reboot
# 启动进入救援(单用户)模式
sudo systemctl rescue

大多数系统都有别名供使用,而无需输入systemctl,如sudo poweroffsudo reboot

使用Systemctl管理Systemd服务和Unit

管理服务

systemd管理对象就是unit,unit的类型可以根据unit文件后缀推断,服务类型的unit以.service结尾。对于大多数服务管理命令,可以省略.service后缀。

启动与停止服务:

1
sudo systemctl start application.service

对于服务管理命令,systemd会自动寻找.service结尾的文件:

1
sudo systemctl start application

停止服务:

1
sudo systemctl stop application.service

重启服务:

1
sudo systemctl restart application.service

重载服务配置文件:

1
sudo systemctl reload application.service

如果不确定服务是否具有重载配置文件的功能,可以使用reload-or-restart,如果无法重载配置文件,就会重启服务以使配置生效:

1
sudo systemctl reload-or-restart application.service

开机启动服务:

1
sudo systemctl enable application.service

这会创建一个从系统服务文件(通常在/lib/systemd/system/etc/systemd/system)到systemd查找自启动文件(通常为/etc/systemd/system/some_target.target.wants)的符号链接。

取消服务自启动(会删除符号链接):

1
sudo systemctl disable application.service

查看服务状态:

1
systemctl status application.service

也可以检查特定的状态,例如查看服务是否正在运行:

1
systemctl is-active application.service

会返回服务的当前状态,通常是active 或 inactive,如果是active,退出代码就是0,方便程序处理结果。

查看服务是否自启动:

1
systemctl is-enabled application.service

会返回enabled 或 disabled,同样根据返回结果退出代码会是0或者1。

检查服务是否处于failed状态,这表明相关unit存在启动问题:

1
systemctl is-failed application.service

如果运行正常,它将返回active状态;如果发生错误,则failed。 如果本机有意停止,则它可能返回unknown或inactive。 退出状态“0”表示发生故障,退出状态“1”表示任何其他状态。

系统状态概览

查看当前活动的unit:

1
2
3
systemctl list-units
# 或者
systemctl

使用–all查看systemd已经加载或者试图加载的unit,不论当前是否活动:

1
systemctl list-units --all

使用–state=查看想看的LOAD, ACTIVE, 或 SUB状态(加上–all否则只能看到active):

1
systemctl list-units --all --state=inactive

只查看感兴趣的unit类型:

1
systemctl list-units --type=service

列出所有unit文件(list-units只会列出systemd尝试解析和加载的文件):

1
systemctl list-unit-files

列出的状态通常为“enabled”, “disabled”, “static”, 或“masked”,static表明unit文件不包含“install”部分,这是启用unit必需的。通常代表此unit是一次性行为或者仅仅是其他unit的依赖项,不能单独运行。

Unit管理

显示systemd已加载到系统中的unit文件:

1
systemctl cat atd.service

显示依赖:

1
systemctl list-dependencies sshd.service

将会显示启动相关unit需按序处理的unit,包括那些required和wanted的uiit。同时只有.target的unit才会递归地显示,若是希望所有依赖递归显示,则加上--all。若是希望逆序显示,使用--reverse。还有些有用的标志,如–before 和 –after,分别显示指定依赖前和后启动的依赖项。

检查unit属性,以key=value格式显示指定unit的属性:

1
systemctl show sshd.service

如果只想显示某个属性,使用-p :

1
systemctl show sshd.service -p Conflicts

systemd还可以通过将unit链接到/dev/null,以将其标记为完全不可启动(不论自动或手动),通过mask命令完成:

1
sudo systemctl mask nginx.service

再使用systemctl list-unit-files检查时,就会发现状态变成了masked。使用unmask命令使其重新可用:

1
sudo systemctl unmask nginx.service

编辑unit文件

使用edit命令会自动打开一个该unit文件片段:

1
sudo systemctl edit nginx.service

这是一个空文件,用于覆盖和增加指令到unit定义中。会在/etc/systemd/system目录下创建一个unit名加.d的目录,例如nginx.service就会创建一个nginx.service.d目录。在此目录下会有一个名为override.conf的文件,在unit被加载时,systemd会在内存中合并原完整文件和此片段文件,片段文件中的指令优先于原文件。

使用–full选项可以创建完整unit文件:

1
sudo systemctl edit --full nginx.service

这会把当前unit文件加载到编辑器中,在退出时保存到/etc/systemd/system,优先于系统unit定义(通常在/lib/systemd/system

若想移除更改,可以删除.d目录或/etc/systemd/system目录下完整定义文件。

1
2
sudo rm -r /etc/systemd/system/nginx.service.d
sudo rm /etc/systemd/system/nginx.service

重载systemd进程以生效:

1
sudo systemctl daemon-reload

使用Target调整系统状态(运行级别)

target是描述系统状态或同步点点特殊unit文件,以.target结尾。target本身并不会做太多事情,而是用来将其他unit组合在一起。

可以使用它来使系统进入某些状态,就像其他init系统使用运行级别一样。 它们用作参考何时某些功能可用,允许你指定所需的状态,而不是产生该状态所需的各个单元。

例如,有一个swap.target用于指示交换已准备就绪。 属于此过程的单元可以通过在其配置中指出它们是WantedBy=RequiredBy= swap.target来与此target同步。 需要交换的unit可以使用Wants=Requires=After=指定此条件,以指示其关系。

获取和设置systemd进程在系统启动时默认的target:

1
2
3
systemctl get-default

sudo systemctl set-default graphical.target

获取可用的target:

1
systemctl list-unit-files --type=target

与运行级别不同,一次可以运行多个target,活动的target表示systemd已尝试启动与target关联的所有unit,并且未尝试再次将其拆除。查看所有活动的target:

1
systemctl list-units --type=target

使用isolate命令,可以启用所有某个target关联的unit,而停止所有非依赖树上的unit,这与init系统中的更改运行级别类似。

例如从graphical.target切换到multi-user.target,前者依赖后者。在进行隔离之前先看一下是否会影响关键服务:

1
systemctl list-dependencies multi-user.target

如果不会影响需要的unit,就可以进行隔离:

1
sudo systemctl isolate multi-user.target

使用Journalctl管理和查看systemd日志

systemd日志背后的推动力之一是集中管理日志,无论消息源自何处。 由于许多引导过程和服务管理都是由systemd进程处理的,因此标准化日志的收集和访问方式是有意义的。 journald的守护程序从所有可用的源中收集数据,并将其以二进制格式存储,以便于动态地进行操作。

systemd默认使用本地时间显示日志,可以使用其自带工具timedatectl修改设置。查看可用时区:

1
timedatectl list-timezones

设置时区:

1
sudo timedatectl set-timezone zone

查看是否使用了正确的时区:

1
timedatectl status

日志查看

1
journalctl

日志默认从最早开始显示。使用UTC时间戳显示:

1
journalctl --utc

时间过滤

只显示本次启动日志:

1
journalctl -b

若想查看过去启动的日志,journalctl也提供了非常方便的工具。如果你的发行版没有默认保存过去的日志,可以如下操作:

1
sudo mkdir -p /var/log/journal

或者

1
sudo nano /etc/systemd/journald.conf

添加如下内容:

1
2
3
. . .
[Journal]
Storage=persistent

使用–list-boots选项查看可用的启动记录:

1
journalctl --list-boots

显示的第一列是相对指针,第二列是boot ID,这两列都可以用于查看特定启动的日志:

1
2
journalctl -b -1
journalctl -b caf0524a1d394ce0bdbcff75b94444fe

时间窗口

可以使用–since 和–until选项限制时间范围。时间戳可以有许多格式,其中绝对时间格式为YYYY-MM-DD HH:MM:SS:

1
journalctl --since "2015-01-10 17:15:00"

如果日期部分缺失,会用0补足:

1
journalctl --since "2015-01-10" --until "2015-01-11 03:00"

journal也可以使用一些相对值,如“yesterday”, “today”, “tomorrow”, 或“now”,对于数字量可在前面加“-” 或 “+” ,也可以在句子中使用“ago” :

1
2
journalctl --since yesterday
journalctl --since 09:00 --until "1 hour ago"

过滤信息

按Unit

1
2
3
journalctl -u nginx.service
journalctl -u nginx.service --since today
journalctl -u nginx.service -u php-fpm.service --since today

按进程/用户/用户组

1
journalctl _PID=8088

也可以使用_UID 或 _GID按用户和用户组过滤,使用id -u username获取用户ID:

1
journalctl _UID=1000 --since today

journal还有许多可用的选项,可以使用如下命令获取:

1
man systemd.journal-fields

例如查看journal记录了哪些用户组的日志:

1
journalctl -F _GID

按组件路径:

1
journalctl /usr/bin/bash

显示Kernel信息:

1
2
journalctl -k
journalctl -k -b -5 #可以组合之前的选项

使用-p选项按权重显示:

1
journalctl -p err -b

权重从高到低分别是:

0: emerg
1: alert
2: crit
3: err
4: warning
5: notice
6: info
7: debug

修改显示

journal默认显示完整信息,可能需要使用->键查看屏幕右方的内容,可以使用–no-full信息截去这部分内容,用引号代替:

1
journalctl --no-full

使用-a选项显示全部信息,无论是否包含不可打印的信息:

1
journalctl -a

journal默认按页显示内容,为了方便信息使用其他标准输出,可以使用–no-pager选项:

1
journalctl --no-pager

使用-o选项更改输出格式,如使用JSON输出:

1
journalctl -b -u nginx -o json

可用格式如下:

cat: Displays only the message field itself.
export: A binary format suitable for transferring or backing up.
json: Standard JSON with one entry per line.
json-pretty: JSON formatted for better human-readability
json-sse: JSON formatted output wrapped to make add server-sent event compatible
short: The default syslog style output
short-iso: The default format augmented to show ISO 8601 wallclock timestamps.
short-monotonic: The default format with monotonic timestamps.
short-precise: The default format with microsecond precision
verbose: Shows every journal field available for the entry, including those usually hidden internally.

活动进程监控

-n选项与tail -n类似,只查看最新内容,默认只显示最近10条:

1
2
journalctl -n
journalctl -n 20

-f选项与tail -f类似,实时输出日志:

1
journalctl -f

Journal维护

查看磁盘使用量:

1
journalctl --disk-usage

删除旧日志:

1
2
3
4
# 删除旧日志直到满足要求的大小
sudo journalctl --vacuum-size=1G
# 只保留一年的日志
sudo journalctl --vacuum-time=1years

通过修改/etc/systemd/journald.conf文件,可以现在journal使用的空间。

设置 含义
SystemMaxUse= 最大磁盘空间使用量
SystemKeepFree= 需要保留的空间
SystemMaxFileSize= 最大单个日志文件大小
RuntimeMaxUse= /run中还未持久化的日志最大大小
RuntimeKeepFree= /run文件系统中需要保留给其他用户的量
RuntimeMaxFileSize= /run中最大单个日志文件大小