参考自https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html ,感谢阮一峰老哥。 同样可以看 Arch Wiki:systemd ,Arch Wiki 真的不错。
由来 历史上,Linux 的启动一直采用 init 进程。
下面的命令用来启动服务。
1 2 3 sudo /etc/init.d/apache2 start service apache2 start
这种方法有两个缺点。
一是启动时间长。init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
二是启动脚本复杂。init 进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
systemd 的诞生 Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。 systemd 成为系统的第一个进程(也就是 PID=1),其他进程都是它的子进程。
systemd 包括的命令
systemd 不是一个命令,而是一组命令。比如 systemctl hostnamectl timedatectl 等
systemctl 常用命令
1 2 3 4 5 6 7 8 9 10 11 sudo systemctl reboot sudo systemctl poweroff sudo systemctl rescue sudo systemctl reboot --firmware-setup
systemd-analyze systemd-analyze 命令用于查看启动耗时。
1 2 3 4 5 6 7 8 9 10 11 systemd-analyze systemd-analyze blame systemd-analyze critical-chain systemd-analyze critical-chain atd.service
hostnamectl hostnamectl 命令用于查看当前主机的信息。
1 2 3 4 5 hostnamectl sudo hostnamectl set-hostname rhel7
localectl localectl 命令用于查看本地化设置。
1 2 3 4 5 6 localectl sudo localectl set-locale LANG=en_US.utf8 sudo localectl set-keymap en_US
timedatectl
timedatectl 命令用于查看当前时区设置。
1 2 3 4 5 6 7 8 9 10 timedatectl timedatectl list-timezones sudo timedatectl set-timezone Asia/Shanghai sudo timedatectl set-time YYYY-MM-DD sudo timedatectl set-time HH:MM:SS
loginctl
loginctl 命令用于查看当前登录的用户。
1 2 3 4 5 6 7 8 loginctl list-sessions loginctl list-users loginctl show-user iuxt
Unit 含义 Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。
Unit 一共分成 12 种。
1 2 3 4 5 6 7 8 9 10 11 12 Service unit: 系统服务 Target unit: 多个 Unit 构成的一个组 Device Unit: 硬件设备 Mount Unit: 文件系统的挂载点 Automount Unit: 自动挂载点 Path Unit: 文件或路径 Scope Unit: 不是由 Systemd 启动的外部进程 Slice Unit: 进程组 Snapshot Unit: Systemd 快照,可以切回某个快照 Socket Unit: 进程间通信的 socket Swap Unit: swap 文件 Timer Unit: 定时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 systemctl list-units systemctl list-units --all systemctl list-units --all --state=inactive systemctl list-units --failed systemctl list-units --type =service
Unit 的状态 systemctl status 命令用于查看系统状态和单个 Unit 的状态。
1 2 3 4 5 6 7 8 systemctl status sysystemctl status bluetooth.service systemctl -H root@rhel7.example.com status httpd.service
除了 status 命令,systemctl 还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
1 2 3 4 5 6 7 8 systemctl is-active application.service systemctl is-failed application.service systemctl is-enabled application.service
Unit 管理 对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 sudo systemctl start apache.service sudo systemctl stop apache.service sudo systemctl restart apache.service sudo systemctl kill apache.service sudo systemctl reload apache.service sudo systemctl daemon-reload systemctl show httpd.service systemctl show -p CPUShares httpd.service sudo systemctl set-property httpd.service CPUShares=500
依赖关系 Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。 systemctl list-dependencies 命令列出一个 Unit 的所有依赖。
1 2 3 systemctl list-dependencies nginx.service 上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用--all参数。 systemctl list-dependencies --all nginx.service
Unit 的配置文件 概述 每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。 Systemd 默认从目录 /etc/systemd/system/
读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录 /usr/lib/systemd/system/
,真正的配置文件存放在那个目录。 systemctl enable 命令用于在上面两个目录之间,建立符号链接关系。
1 2 3 4 5 6 7 8 9 10 sudo systemctl enable clamd@scan.service sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service' 如果配置文件里面设置了开机启动,systemctl enable 命令相当于激活开机启动。 与之对应的,systemctl disable 命令用于在两个目录之间,撤销符号链接关系,相当于撤销开机启动。 sudo systemctl disable clamd@scan.service 配置文件的后缀名,就是该 Unit 的种类,比如sshd.socket。如果省略,Systemd 默认后缀名为.service,所以sshd会被理解成sshd.service。
配置文件的状态 systemctl list-unit-files 命令用于列出所有配置文件。
1 2 3 4 5 6 systemctl list-unit-files systemctl list-unit-files --type =service 这个命令会输出一个列表。
systemctl list-unit-files
1 2 3 4 UNIT FILE STATE chronyd.service enabled clamd@.service static clamd@scan.service disabled
这个列表显示每个配置文件的状态,一共有四种。
1 2 3 4 enabled:已建立启动链接 disabled:没建立启动链接 static:该配置文件没有[Install]部分(无法执行),只能作为其他配置文件的依赖 masked:该配置文件被禁止建立启动链接
注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到的 systemctl status 命令。
一旦修改配置文件,就要让 Systemd 重新加载配置文件,然后重新启动,否则修改不会生效。
1 2 sudo systemctl daemon-reload sudo systemctl restart httpd.service
配置文件的格式 1 2 查看配置文件的内容 systemctl cat atd.service
1 2 3 4 5 6 7 8 9 [Unit] Description=ATD daemon [Service] Type=forking ExecStart=/usr/bin/atd [Install] WantedBy=multi-user.target
配置文件的区块 [Unit] 区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。它的主要字段如下。
1 2 3 4 5 6 7 8 9 10 Description: 简短描述 Documentation: 文档地址 Requires: 当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败 Wants: 与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败 BindsTo: 与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行 Before: 如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动 After: 如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动 Conflicts: 这里指定的 Unit 不能与当前 Unit 同时运行 Condition...: 当前 Unit 运行必须满足的条件,否则不会运行 Assert...: 当前 Unit 运行必须满足的条件,否则会报启动失败
[Install] 通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它的主要字段如下。
1 2 3 4 WantedBy: 它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中 RequiredBy: 它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中 Alias: 当前 Unit 可用于启动的别名 Also: 当前 Unit 激活(enable)时,会被同时激活的其他 Unit
[Service] 区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的主要字段如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Type: 定义启动时的进程行为。它有以下几种值。 Type=simple: 默认值,执行ExecStart指定的命令,启动主进程 Type=forking: 以 fork 方式从父进程创建子进程,创建后父进程会立即退出 Type=oneshot: 一次性进程,Systemd 会等当前服务退出,再继续往下执行 Type=dbus: 当前服务通过D-Bus启动 Type=notify: 当前服务启动完毕,会通知Systemd,再继续往下执行 Type=idle: 若有其他任务执行完毕,当前服务才会运行 ExecStart: 启动当前服务的命令 ExecStartPre: 启动当前服务之前执行的命令 ExecStartPost: 启动当前服务之后执行的命令 ExecReload: 重启当前服务时执行的命令 ExecStop: 停止当前服务时执行的命令 ExecStopPost: 停止当其服务之后执行的命令 RestartSec: 自动重启当前服务间隔的秒数 Restart: 定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog TimeoutSec: 定义 Systemd 停止当前服务之前等待的秒数 Environment: 指定环境变量
Target 启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。
简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于 “ 状态点 “,启动某个 Target 就好比启动到某种状态。
传统的 init 启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 systemctl list-unit-files --type =target systemctl list-dependencies multi-user.target systemctl get-default sudo systemctl set-default multi-user.target sudo systemctl isolate multi-user.target
Target 与 传统 RunLevel 的对应关系如下。
1 2 3 4 5 6 7 8 9 Traditional runlevel New target name Symbolically linked to... Runlevel 0 | runlevel0.target -> poweroff.target Runlevel 1 | runlevel1.target -> rescue.target Runlevel 2 | runlevel2.target -> multi-user.target Runlevel 3 | runlevel3.target -> multi-user.target Runlevel 4 | runlevel4.target -> multi-user.target Runlevel 5 | runlevel5.target -> graphical.target Runlevel 6 | runlevel6.target -> reboot.target
它与 init 进程的主要差别如下。
(1)默认的 RunLevel(在/etc/inittab 文件设置)现在被默认的 Target 取代,位置是/etc/systemd/system/default.target,通常符号链接到 graphical.target(图形界面)或者 multi-user.target(多用户命令行)。
(2)启动脚本的位置,以前是/etc/init.d 目录,符号链接到不同的 RunLevel 目录 (比如/etc/rc3.d、/etc/rc5.d 等),现在则存放在/lib/systemd/system 和/etc/systemd/system 目录。
(3)配置文件的位置,以前 init 进程的配置文件是/etc/inittab,各种服务的配置文件存放在/etc/sysconfig 目录。现在的配置文件主要存放在/lib/systemd 目录,在/etc/systemd 目录里面的修改可以覆盖原始设置。
日志管理 Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用 journalctl 一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf。
journalctl 功能强大,用法非常多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 sudo journalctl sudo journalctl -k sudo journalctl -b sudo journalctl -b -0 sudo journalctl -b -1 sudo journalctl --since="2012-10-30 18:17:16" sudo journalctl --since "20 min ago" sudo journalctl --since yesterday sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00" sudo journalctl --since 09:00 --until "1 hour ago" sudo journalctl -n sudo journalctl -n 20 sudo journalctl -f sudo journalctl /usr/lib/systemd/systemd sudo journalctl _PID=1 sudo journalctl /usr/bin/bash sudo journalctl _UID=33 --since today sudo journalctl -u nginx.service sudo journalctl -u nginx.service --since today sudo journalctl -u nginx.service -f journalctl -u nginx.service -u php-fpm.service --since today sudo journalctl -p err -b sudo journalctl --no-pager sudo journalctl -b -u nginx.service -o json sudo journalctl -b -u nginx.serviceqq -o json-pretty sudo journalctl --disk-usage sudo journalctl --vacuum-size=1G sudo journalctl --vacuum-time=1years
user
systemd 会给每个用户生成一个 systemd 实例,用户可以在这个实例下管理服务,启动、停止、启用以及禁用他们自己的单元。这个能力大大方便了那些通常在特定用户下运行的守护进程和服务
/usr/lib/systemd/user/
这里存放的是各个软件包安装的服务。
~/.local/share/systemd/user/
这里存放的是 HOME 目录中已安装的软件包的单元。
/etc/systemd/user/
这里存放的是由系统管理员维护的系统范围的用户服务。
~/.config/systemd/user/
这里存放的是用户自身的服务。
当 systemd 用户实例启动时,它会将 default.target
带起来。其他用户单元可以通过 systemctl --user
来管理。
例子 执行自定义脚本 通过 systemd 进行开机自启动脚本
vim /etc/systemd/system/custom.service
1 2 3 4 5 6 7 8 9 [Unit] Description = Custom Startup Service[Service] Type = simpleExecStart = /opt/scripts/custom.sh[Install] WantedBy = multi-user.target
sudo systemctl enable custom.service