Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。
守护进程
守护进程(daemon)是指在UNIX或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控。此类程序会被以进程的形式初始化。守护进程程序的名称通常以字母“d”结尾:例如,syslogd就是指管理系统日志的守护进程。用户退出session之后,“后台任务是否会继续执行”是判定这一任务是否为“守护进程”的依据。
Systemd概述
Systemd出现前,Linux的服务已知采用init进程启动,例如运行下面的命令可以启动apache服务:
1 2 3
| sudo /etc/init.d/apache2 start
service apache2 start
|
优于init是串行启动,只有前一个进程启动结束才能继续,因此这种方法启动时间比较长,并且init进程只执行启动脚本,不管其他事情,因此启动脚本会非常复杂。
Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。
根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。
Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。下图是Systemd体系架构图:
系统管理
Systemd不是一个命令,而是一组涉及到系统方方面面的一组命令。
systemctl
Systemd 的主命令,用于管理系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| $ sudo systemctl reboot
$ sudo systemctl poweroff
$ sudo systemctl halt
$ sudo systemctl suspend
$ sudo systemctl hibernate
$ sudo systemctl hybrid-sleep
$ sudo systemctl rescue
|
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
查看主机信息
1 2 3 4 5 6 7 8 9 10 11 12
| $ hostnamectl Static hostname: ubuntu Icon name: computer-vm Chassis: vm Machine ID: Boot ID: Virtualization: vmware Operating System: Ubuntu 18.04.6 LTS Kernel: Linux 5.4.0-150-generic Architecture: x86-64
$ sudo hostnamectl set-hostname test
|
localectl
显示本地化信息:
1 2 3 4 5 6 7 8
| $ localectl System Locale: LANG=en_US.UTF-8 VC Keymap: n/a X11 Layout: us X11 Model: SKIP
$ sudo localectl set-locale LANG=en_GB.utf8 $ sudo localectl set-keymap en_GB
|
timedatectl
显示当前时区设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ timedatectl Local time: Fri 2023-11-17 03:42:56 PST Universal time: Fri 2023-11-17 11:42:56 UTC RTC time: Fri 2023-11-17 11:42:56 Time zone: America/Los_Angeles (PST, -0800) System clock synchronized: yes systemd-timesyncd.service active: yes RTC in local TZ: no
$ timedatectl list-timezones
$ sudo timedatectl set-timezone Asia/Shanghai $ sudo timedatectl set-time YYYY-MM-DD $ sudo timedatectl set-time HH:MM:SS
|
loginctl
查看当前登录的用户。
1 2 3 4 5 6 7 8 9 10 11 12
| $ loginctl SESSION UID USER SEAT TTY c1 121 gdm seat0 tty1 2 1000 user seat0 tty2
$ loginctl list-sessions
$ loginctl list-users
$ loginctl show-user user
|
Unit
Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。
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:定时器
查看unit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $ 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 dbus.service
$ systemctl -H root@remotehost status httpd.service
|
Unit管理
我们常用的用于启动和停止 Unit命令如下:
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 apache.service
$ systemctl show -p CPUShares apache.service
$ sudo systemctl set-property apache.service CPUShares=500
|
依赖关系
Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。
systemctl list-dependencies
命令列出一个 Unit 的所有依赖,上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用--all
参数。
1 2 3
| $ systemctl list-dependencies nginx.service
$ systemctl list-dependencies --all nginx.service
|
配置文件
每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。
Systemd 默认从目录/etc/systemd/system/
读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/
,真正的配置文件存放在那个目录。systemctl enable
命令用于在上面两个目录之间,建立符号链接关系。
配置文件的后缀名,就是该 Unit 的种类,比如sshd.socket
。如果省略,Systemd 默认后缀名为.service
,所以sshd
会被理解成sshd.service
systemctl list-unit-files
命令用于列出所有配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| $ systemctl list-unit-files UNIT FILE STATE proc-sys-fs-binfmt_misc.automount static -.mount generated dev-hugepages.mount static dev-mqueue.mount static media-floppy0.mount generated proc-sys-fs-binfmt_misc.mount static run-vmblock\x2dfuse.mount enabled snap-bare-5.mount enabled
$ systemctl list-unit-files --type=service UNIT FILE STATE accounts-daemon.service enabled acpid.service disabled alsa-restore.service static alsa-state.service static alsa-utils.service masked anacron.service enabled apparmor.service enabled
|
- enabled:已建立启动链接
- disabled:没建立启动链接
- static:该配置文件没有
[Install]
部分(无法执行),只能作为其他配置文件的依赖
- masked:该配置文件被禁止建立启动链接
一旦修改配置文件,就要让 Systemd 重新加载配置文件,然后重新启动,否则修改不会生效:
1 2
| $ sudo systemctl daemon-reload $ sudo systemctl restart xxx.service
|
配置文件格式
systemctl cat
命令可以查看配置文件的内容,配置文件分成几个区块,每个区块的第一行,是用方括号表示的区别名,比如[Unit]
。注意,配置文件的区块名和字段名,都是大小写敏感的。区块内部是一些等号连接的键值对。
配置文件字段信息详见:systemd.unit
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 10
| 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
|
systemd与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
目录里面的修改可以覆盖原始设置。
journalctl
Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl
一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf
常用的查看日志命令:
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
|