每天学五分钟 Liunx 0110 | 服务篇:守护进程 systemd


有些进程会在系统上运行较长时间,如前面的 Hello World 程序运行时产生的进程。有些进程运行瞬间就结束了,如执行 ps 命令产生的进程,也有的进程会常驻在内存中,提供相应的服务,这样的进程称为守护进程(daemon),它所提供的功能叫做服务。
 
这样的守护进程有很多。比如,sshd(d 表示 daemon) 守护进程提供 ssh 登陆连接服务,crond 守护进程提供周期性处理任务服务,等等。
Liunx 也提供了一个为系统启动管理提供完整解决方案的守护进程 systemd。
 

systemd 

systemd 是系统启动的第一个守护进程,类似于一个大管家,它为系统启动和管理提供了相当完整的服务。
传统的 Liunx 发行版(CentOS5 / CentOS6)采用的是 init 进程作为系统的启动进程,它的缺点是启动时间长(串行启动,前一个进程启动完才能启动下一个进程)并且启动脚本复杂,而 systemd 解决了这些问题。
systemd 的示意图如下:
 
 

systemd 命令

systemd 是一组命令的集和,先列出常用的命令:
系统管理
systemctl
重启系统
sudo systemctl reboot
暂停系统
sudo systemctl suspend
CPU 停止工作
sudo systemctl halt
关闭系统,切断电源
sudo systemctl poweroff 
systemd-analyze
查看启动耗时
systemd-analyze
查看每个服务启动耗时
systemd-analyze blame
查看启动过程流
systemd-analyze critical-chain
查看指定服务的启动流
systemd-analyze critical-chain sshd.service
hostnamectl
查看当前主机信息
hostnamectl
设置主机名
sudo hostnamectl set-hostname ***
localectl
查看本地化设置
localectl
timedatectl
查看当前时区设置
timedatectl
显示所有可用时区
timedatectl list-timezones
设置当前时区
sudo timedatectl set-timezone Africa/Juba
Unit
systemctl list-units
查看系统正在运行的单元
systemctl list-units
列出系统中所有单元
systemctl list-units --all
列出所有加载失败的单元
systemctl list-units --failed
列出所有正在运行,类型为服务的单元
systemctl list-units --type=service
systemctl status
查看系统状态
systemctl status
查看服务状态
systemctl status ***.service
查看远端主机的服务状态
systemctl -H user@hostname status ***.service
unit 管理
启动服务
sudo systemctl start ***.service
停止服务
sudo systemctl stop ***.service
重启服务
sudo systemctl restart ***.service
杀死服务产生的所有子进程
sudo systemctl kill ***.service
重新加载服务配置文件
sudo systemctl reload ***.service
重新加载所有修改单元的配置文件
sudo systemctl daemon-reload
显示 unit 的底层参数
sudo systemctl show ***.service
systemctl list-dependencies
列出服务的依赖关系
systemctl list-dependencies ***.service
列出服务的反向依赖关系
systemctl list-dependencies --reverse ***.service
查看 target 包含的 unit
systemctl list-dependencies ***.target
unit 配置文件
查看 unit 配置文件的内容
systemctl cat ***.service
查看所有配置文件
systemctl list-unit-files
查看指定类型的配置文件
systemctl list-unit-files --type=service
Target
查看系统的所有 target
systemctl list-unit-files --type=target
查看 target 包含的 unit
systemctl list-dependencies ***.target
查看启动时的默认 target
systemctl get-default
日志管理
journalctl
查看本次系统启动的所有日志
journalctl 
查看指定 Unit 的日志
journalctl -u ***.service
滚动显示最新的日志
journalctl -f
查看指定时间的日志
journalctl --since "2020-05-06 01:00" --until "2020-05-06 03:00"
 
简单介绍个比较重要的命令 systemd-analyze ciritical-chain :
[root@lianhua ~]$ systemd-analyze critical-chain sshd.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.
 
sshd.service +16ms
└─cloud-init.service @6.503s +9.732s
  └─network.service @3.352s +3.121s
    └─network-pre.target @3.348s
      └─cloud-init-local.service @1.665s +1.682s
        └─dbus.socket @1.659s
          └─sysinit.target @1.628s
            └─systemd-update-utmp.service @1.614s +13ms
              └─auditd.service @1.424s +182ms
                └─systemd-tmpfiles-setup.service @1.394s +16ms
                  └─rhel-import-state.service @1.341s +40ms
                    └─local-fs.target @1.325s
                      └─ephemeral.mount @747ms +577ms
                        └─local-fs-pre.target @728ms
                          └─lvm2-monitor.service @368ms +359ms
                            └─lvm2-lvmetad.service @484ms
                              └─lvm2-lvmetad.socket @329ms
                                └─-.slice
 
输出结果中,"@" 后面的时刻表示该单元的启动时刻; "+"后面的时长表示该单元总计花了多长时间才完成启动。需要注意的是, 这些信息可能具有误导性, 因为花费较长时间启动的单元, 有可能只是在等待另一个依赖单元完成启动,服务在启动时并不是按顺序启动的。
 

Unit

systemd 管理的多个系统资源统称为 Unit,共有 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:定时器
 
查看 sshd 这个 service unit 的状态:
[root@lianhua ~]$ systemctl status sshd.service
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2019-11-01 18:35:20 CST; 6 months 3 days ago
     Docs: man:sshd(8)
           man:sshd_config(5)
Main PID: 8621 (sshd)
   Memory: 24.7M
   CGroup: /system.slice/sshd.service
           └─8621 /usr/sbin/sshd -D
 
Nov 01 18:35:20 lianhua systemd[1]: Starting OpenSSH server daemon...
 
查看启动 sshd.service 需要依赖的 unit:
[root@lianhua ~]$ systemctl list-dependencies sshd.service
sshd.service
● ├─sshd-keygen.service
● ├─system.slice
● └─basic.target
●   ├─microcode.service
●   ├─rhel-dmesg.service
●   ├─selinux-policy-migrate-local-changes@targeted.service
...
 
查看哪些 unit 需要依赖 sshd.service:
[root@lianhua ~]$ systemctl list-dependencies --reverse sshd.service
sshd.service
● ├─cloud-init.service
● └─multi-user.target
●   └─graphical.target
 
查看 sshd.service 的配置文件:
[root@lianhua ~]$ systemctl cat sshd.service
# /usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
 
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
 
[Install]
WantedBy=multi-user.target
 
可以看出,配置文件共分为三块 Unit,Service 和 Install,每块参数介绍如下:
[Unit]
Description:对 Unit 进行简单描述的字符串。
Documentation:对 Unit 详细说明的文档。
After:强调单元间的启动先后顺序,After 是在后面指定单元之后启动。
Before:对应于 After,强调单元间的先后顺序,在后面指定单元之前启动。
Requires:设置单元间的依赖关系,注意 After 和 Before 只强调了启动顺序,并没有设置依赖关系。Requires 设置单元强依赖指定的单元,如果指定单元启动失败,将不会启动该单元。
Wants:弱依赖关系,指定的 Unit 如果启动失败当前 Unit 还是会启动。
BindsTo: 与 Requires 类似,但是依赖性更强。在 Requires 中被依赖单元如果条件检查失败或者单元主动停止,并不会使得依赖单元也跟着一起停止,使用 BindsTo 就能实现如果被依赖单元停止,依赖单元跟着会停止。
Conflicts:指定单元间的冲突关系,如果指定的单元启动,当前单元将不会启动,当前单元启动则指定的单元必须停止。
 
[Service]
Unit 执行的主体。
Type: 设置进程的启动类型,必须设为 simple,exec,forking,oneshot,dbus,notify 和 idle:
  • simple:默认值,使用主进程执行 ExecStart 指定的命令。
  • forking:以 fork 的方式从父进程中创建子进程,创建后父进程立即退出。
  • oneshot:一次性进程,systemd 等待当前服务退出,再往下执行。
  • dbus:当前服务通过 D-Bus 启动。
  • notify:当前服务启动完毕,通知 systemd ,再继续往下执行。
  • idle: 若有其它服务执行完毕,当前服务才会运行。
ExecStart:启动当前服务的命令。
EnvironmentFile:当前服务的环境配置文件,ExecStart 中的变量 $OPTIONS 即来自该配置文件。
ExecReload:当前服务重新载入配置时需要执行 ExecReload 指定的命令行,其中,$MAINPID 是个特殊的环境变量,它表示主进程的 PID。
KillMode:设置在单元停止时,杀死进程的方法。process 表示仅杀死主进程。
Restart:当服务进程正常退出,异常退出,被杀死,超时的时候是否重启该服务。on-failue 表示仅在服务异常退出时重启该服务。
RestartSec:设置服务重启前暂停多长时间,默认单位为 s。
 
[Install]
Install 用来定义 Unit 如何启动,以及是否开机自启动。
WantedBy:在使用 systemctl enable 启用此单元时, 将会在每个列表单元的 .wants/ 目录中创建一个指向该单元文件的软连接。相当于为每个列表中的单元文件添加 Wants= 单元选项。 这样当列表中的任意一个单元启动时,该单元都会被启动。
RequiredBy:类似于 WantedBy 相当于添加 Requires= 单元选项。
 

Unit 配置文件状态

 
Systemd 默认从目录 /etc/systemd/system/ 读取 Unit 的配置文件。但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/,真正的配置文件存放在这个目录。如果两个目录之间建立了符号链接则表示该 Unit 建立了启动链接。
 
命令 systemctl list-unit-files 可以 show 出各 Unit 配置文件的状态:
[root@lianhua ~]$ systemctl list-unit-files
UNIT FILE                                     STATE
tmp.mount                                     disabled
brandbot.path                                 enabled
auth-rpcgss-module.service                    static
autofs.service                                disabled
systemd-timedated.service                     masked
...
 
Unit 文件的状态有四种:
enabled:已建立启动链接;
disabled:未建立启动链接,但是 Install 区块中有可以建立启动链接的值;
masked:该 Unit 配置文件被禁止建立启动链接,对应的是 /etc/systemd/system/ 目录软链接指向了 /dev/null;
static:该配置文件没有 Install 部分,只能作为其它 Unit 的依赖被启用;
 
分别查看四种状态下的文件配置信息:
# autofs.service disabled
[root@lianhua ~]# systemctl cat autofs.service
# /usr/lib/systemd/system/autofs.service
[Unit]
...
[Service]
...
[Install]
WantedBy=multi-user.target
[root@lianhua ~]# ll /etc/systemd/system/multi-user.target.wants/ | grep autofs.service
[root@lianhua ~]#
 
# brandbot.path enabled
[root@lianhua ~]$ systemctl cat brandbot.path
# /usr/lib/systemd/system/brandbot.path
[Unit]
...
[Path]
...
[Install]
WantedBy=multi-user.target
[root@lianhua ~]$ ll /etc/systemd/system/multi-user.target.wants/ | grep brand
lrwxrwxrwx. 1 root root 37 May  9  2018 brandbot.path -> /usr/lib/systemd/system/brandbot.path

 
# systemd-timedated.service masked
[root@lianhua ~]# ll /etc/systemd/system | grep systemd-timedated.service
lrwxrwxrwx. 1 root root    9 Aug 12  2018 systemd-timedated.service -> /dev/null
 
 
# auth-rpcgss-module.service static
[root@lianhua ~]# systemctl cat auth-rpcgss-module.service
[Unit]
...
[Service]
...
 
命令 systemctl enable 和 systemctl diable 分别可以给 Unit 建立启动链接(前提是它们可以被建立启动链接) 和撤销启动链接,命令 systemctl is-enable 可以查看 Unit 是不是 enable 的,举例:
[root@lianhua ~]# systemctl is-enabled autofs.service
disabled
[root@lianhua ~]# systemctl enable autofs.service
Created symlink /etc/systemd/system/multi-user.target.wants/autofs.service → /usr/lib/systemd/system/autofs.service.
[root@lianhua ~]# systemctl is-enabled autofs.service
enabled
 
 
除了命令查看 Unit 是否 enable 之外,还有一种通过 systemctl status 查看 Unit 是否 enable 的方法:
[root@lianhua ~]# systemctl status autofs.service
● autofs.service - Automounts filesystems on demand
   Loaded: loaded (/usr/lib/systemd/system/autofs.service; enabled; vendor preset: disabled)
   Active: inactive (dead)
 
第一行 Loaded 的第一个 enabled 表示当前 Unit 是否开机自启动,也就是 systemctl is-enable 要 show 的值。
第二个 disabled 表示 systemd 预设(preset)文件中是否默认启用(enable)或停用(disable) Unit。可以从以下目录中来查看 Unit 的预设文件:
/etc/systemd/system-preset/*.preset
/run/systemd/system-preset/*.preset
/usr/lib/systemd/system-preset/*.preset
/etc/systemd/user-preset/*.preset
/run/systemd/user-preset/*.preset
/usr/lib/systemd/user-preset/*.preset
 
举例:
[root@lianhua ~]# ll /usr/lib/systemd/system-preset/
total 24
-rw-r--r--. 1 root root  264 Sep 25  2019 85-display-manager.preset
-rw-r--r--. 1 root root 3982 Sep 25  2019 90-default.preset
-rw-r--r--. 1 root root  951 Jun 22  2018 90-systemd.preset
 
[root@lianhua ~]# cat /usr/lib/systemd/system-preset/90-systemd.preset
enable remote-fs.target
disable console-getty.service
disable debug-shell.service
 
预设文件的格式是 “优先级-策略名.preset”,其中优先级数字越小表示优先级越高。一般软件包自带的预设文件应放到 /usr/lib 目录下,系统管理员设定的预设文件放在 /etc 目录下, 对于不同目录下的同名预设文件仅以优先级最高的目录中的那一个为准,即 /etc/ 的优先级最高、 /run/ 的优先级居中、 /usr/lib/ 的优先级最低。
预设文件的内容 enable 表示默认启用指定的 Unit,disable 表示默认停用指定的单元。
 
 
现在试想一种情况,如果 service(unit) 的配置文件都写好了,但是需要临时改动执行 service 的 user ,这时候需要重新写配置文件吗?
答案是不需要,可以通过 systemd 的 Drop-in 机制重新更改 Unit 的配置,比如:
[root@lianhua process]$ systemctl status autofs.service
● autofs.service - Automounts filesystems on demand
   Loaded: loaded (/usr/lib/systemd/system/autofs.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2019-08-05 17:42:46 CST; 9 months 0 days ago
  Process: 23921 ExecReload=/usr/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
 
[root@lianhua process]$ cat /usr/lib/systemd/system/autofs.service.d/app.conf
[Service]
User=
User=app
[root@lianhua process]$ systemctl daemon-reload
[root@lianhua process]$ systemctl restart autofs.service
[root@lianhua process]$ systemctl status autofs.service
● autofs.service - Automounts filesystems on demand
   Loaded: loaded (/usr/lib/systemd/system/autofs.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/autofs.service.d
           └─app.conf
   Active: active (running) since Mon 2019-08-05 17:42:46 CST; 9 months 0 days ago
 
systemd 中使用 Drop-in 机制需要在 unit 的同级目录下建 ***.d 的目录,目录下配置以 .conf 结尾的文件。
文件中第一行表示更改的配置块,第一个 User= 表示取消服务执行的用户,第二个 User 表示将服务执行的用户指定为给定值,示例中配置的是 app 这个用户。
配置完之后,需要重新加载 systemd 的配置文件,然后重启相关 unit,检查 unit 的状态发现多了一个 Drop-In 文件,并且状态时 active 的。
 

Target

Target 是一类特殊的 Unit,它表示一个 Unit 组,systemd 在启动 Target 的时候,会启动 Target 包含的所有 Unit。所以 systemd 启动到某个 target 相当于是启动到了某个状态。
查看 target 状态:
[root@lianhua ~]# systemctl cat cloud-config.target
[Unit]
Description=Cloud-config availability
Wants=cloud-init-local.service cloud-init.service
After=cloud-init-local.service cloud-init.service
[root@lianhua ~]# systemctl status cloud-config.target
● cloud-config.target - Cloud-config availability
   Loaded: loaded (/usr/lib/systemd/system/cloud-config.target; static; vendor preset: disabled)
   Active: active since Fri 2020-03-13 09:18:36 UTC; 1 months 22 days ago
 

path unit

[root@lianhua ~]# systemctl status systemd-ask-password-wall.path
● systemd-ask-password-wall.path - Forward Password Requests to Wall Directory Watch
   Loaded: loaded (/usr/lib/systemd/system/systemd-ask-password-wall.path; static; vendor preset: disabled)
   Active: active (waiting) since Fri 2020-03-13 09:17:52 UTC; 1 months 22 days ago
     Docs: man:systemd-ask-password-console.service(8)
 
[root@lianhua ~]# systemctl cat systemd-ask-password-wall.path
[Unit]
Description=Forward Password Requests to Wall Directory Watch
...
 
[Path]
DirectoryNotEmpty=/run/systemd/ask-password
MakeDirectory=yes
[root@lianhua ~]# systemctl status systemd-ask-password-wall
● systemd-ask-password-wall.service - Forward Password Requests to Wall
   Loaded: loaded (/usr/lib/systemd/system/systemd-ask-password-wall.service; static; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:systemd-ask-password-console.service(8)
 
path 也是众多 unit 的一种,它是 systemd 用来监视文件系统路径,以支持基于路径启动的单元。
每个路径单元都必须有一个与其匹配的单元,以用于在路径发生变化时启动。匹配的单元可以通过 Unit= 选项明确指定。若未指定,则默认是与该单元名称相同的 .service 单元(不算后缀)。例如 systemd-ask-password-wall.path 默认匹配 systemd-ask-password-wall.service 单元。
<path 的具体参数配置可看这里>
 

mount unit

如果一个 path 单元的文件系统路径位于另一个 mount 单元之下, 那么将会自动获得对其所依赖的挂载点单元的 Requires= 与 After= 依赖。
mount 同样的是众多 unit 的一种,它是 systemd 用来管理文件系统挂载点的单元。
[root@lianhua process]$ systemctl status build.mount
● build.mount - /build
   Loaded: loaded (/etc/fstab; bad; vendor preset: disabled)
   Active: active (mounted) since Mon 2019-08-05 17:42:44 CST; 9 months 0 days ago
    Where: /build
     What: lianhua.net:/vol/test/build/build
     Docs: man:fstab(5)
           man:systemd-fstab-generator(8)
   Memory: 0B
 
Aug 05 17:42:44 lianhua systemd[1]: Mounting /build...
Aug 05 17:42:44 lianhua systemd[1]: Mounted /build.
[root@lianhua process]$ systemctl cat build.mount
 
[Unit]
SourcePath=/etc/fstab
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
Before=remote-fs.target
 
[Mount]
What=lianhua.net:/vol/test/build/build
Where=/build
Type=nfs
Options=soft,intr,retry=1,rw,rsize=32768,wsize=32768
[root@lianhua process]$ df -hT | grep /build
lianhua.net:/vol/test/build/build nfs        21T   17T  4.3T  80% /build
 
mount 单元中,参数 where 表示挂载点目录,需要指明绝对路径,参数 what 表示被挂载对象,同样需要指明绝对路径。参数 type 表示挂载的文件系统类型。
 
 
 
(完)
posted @ 2020-05-06 01:01  lubanseven  阅读(555)  评论(0编辑  收藏  举报