From the project web page:
systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system. systemd provides aggressive parallelization capabilities, uses socket and D-Bus activation for starting services, offers on-demand starting of daemons, keeps track of processes using Linux control groups, maintains mount and automount points, and implements an elaborate transactional dependency-based service control logic. systemd supports SysV and LSB init scripts and works as a replacement for sysvinit. Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution.
支持的主要单元:服务单元(.service),挂载单元(.mount),目标单元(.target)等
默认情况下,systemd会在启动单元的同时启动其所有的Requires和Wants依赖组件。
Requires和Wants定义依赖关系并没有设定顺序,使用顺序关键字(Before和After)来设定顺序
Before:当前单元会在Before中列出的单元之前启动
After: 当前单元在After中列出的单元之后启动
记住这个原则即可:
不要更改系统单元目录,因为它由系统来维护。可以在系统配置目录中保存你的自定义设置。在选择更改/usr还是更改/etc时,永远选择/etc
# There are two safe ways to modify a unit without touching the original file:
# create a new unit file which overrides the original unit or create drop-in snippets which are applied on top of the original unit.
# Replace or Drop-in unit files, with parameter --full is Replace mode, otherwise Drop-in mode
$ sudo systemctl edit [--full] ssh.service
# To revert any changes to a unit made using systemctl edit
$ systemctl revert ssh.service
默认情况下,systemctl edit使用nano作为编辑器,使用如下方法改变使用vi作为编辑器
$ vi ~/.bashrc
export SYSTEMD_EDITOR=vim
$ sudo visudo
Defaults env_keep += "SYSTEMD_EDITOR"
Install节
sshd.service
[Unit]
Description=OpenSSH server daemon
After=syslog.target network.target auditd.service
[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
单元文件中的[Install]区块很重要,因为它告诉我们怎样使用systemd的WantedBy和RequiredBy依赖关系
这部分配置的目标模块通常是特定运行目标的.target文件,用来使得服务在系统启动时自动运行。这个区段可以包含三种启动约束:
WantedBy:和 Unit 段的 Wants 作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。
它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入 /etc/systemd/system目录下面以
RequiredBy:和 Unit 段的 Requires作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。
它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入 /etc/systemd/system目录下面以
Also:当前 Unit enable/disable 时,同时 enable/disable 的其他 Unit
Alias:当前 Unit 可用于启动的别名
Unit 模板文件的写法与普通的服务 Unit 文件基本相同,不过 Unit 模板的文件名是以 @ 符号结尾的。通过模板启动服务实例时,需要在其文件名的 @ 字符后面附加一个参数字符串。
Systemd 在运行服务时,总是会先尝试找到一个完整匹配的 Unit 文件,如果没有找到,才会尝试选择匹配模板。
Unit状态:
enabled:已建立启动链接
disabled:没建立启动链接
static:该配置文件没有 [Install] 部分(无法执行),只能作为其他配置文件的依赖
masked:该配置文件被禁止建立启动链接
systemd启动流程
target配置流程(实际启动时从最底层的local-fs-pre.target开始执行)
-> default.target (=graphical.target by default)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
This tells systemd to start everything in the multi-user.target before starting the graphical target.
Once that's done, the "Wants" entry tells systemd to start the display-manager.service service (/etc/systemd/system/display-manager.service), which runs the GNOME display manager (/usr/sbin/gdm).
-> multi-user.target
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
This tells systemd to start everything in the /lib/systemd/system/basic.target target before starting the other multi-user services.
After that, for the multi-user.target, all units (services, targets, etc.) in the /etc/systemd/system/multi-user.target.wants and /lib/systemd/system/multi-user.target.wants directories are started.
When you enable a service, a symbolic link is placed in the /etc/systemd/system/multi-user.target.wants directory.
That directory is where you will find links to most of the services you think of as starting in multi-user mode (printing, cron, auditing, SSH, and so on).
-> basic.target
Requires=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount
This points systemd to the /lib/systemd/system/sysinit.target, which must start before the basic.target can continue.
The basic.target target file starts the firewalld and microcode services from the /etc/systemd/system/basic.target.wants directory and services for SELinux, kernel messages, and loading modules from the /lib/systemd/system/basic.target.wants directory.
-> sysinit.target
Conflicts=emergency.service emergency.target
Wants=local-fs.target swap.target
After=local-fs.target swap.target emergency.service emergency.target
Besides mounting file systems and enabling swap devices, the sysinit.target starts targets, services, and mounts based on units contained in the /lib/systemd/system/sysinit.target.wants directory.
These units enable logging, set kernel options, start the udevd daemon to detect hardware, and allow file system decryption, among other things.
The /etc/systemd/system/sysinit.target.wants directory contains services that start iSCSI, multipath, LVM monitoring and RAID services.
-> local-fs.target
Conflicts=shutdown.target
After=local-fs-pre.target
There are no services associated with the local-fs-pre.target target (you could add some to a "wants" directory if you like).
However, units in the /lib/systemd/system/local-fs.target.wants directory import the network configuration from the initramfs, run a file system check (fsck) on the root file system when necessary, and remounting the root file system (and special kernel file systems) based on the contents of the /etc/fstab file.
启动时通过/etc/systemd/system/unit.target.wants目录来决定哪些服务会被当前target启动
systemctl service和target相关命令
# 获取当前正在使用的运行目标
# systemctl list-units --type=target
# 只重新加载unit单元的配置
$ systemctl reload unit:
# 重新加载所有的单元配置
$ systemctl daemon-reload:
# 显示单元的配置文件或配置参数
$ systemctl [cat|show] docker.service
# 显示单元的依赖关系
$ systemctl list-dependencies docker.service
# 查看当前系统的所有 Target
$ systemctl list-unit-files --type=target
# 查看一个 Target 包含的所有 Unit
$ systemctl list-dependencies multi-user.target
# 查看启动时的默认 Target
$ systemctl get-default
# 设置启动时的默认 Target
$ sudo systemctl set-default multi-user.target
# 切换 Target 时,默认不关闭前一个 Target 启动的进程,systemctl isolate 命令改变这种行为,关闭前一个 Target 里面所有不属于后一个 Target 的进程
# This will only change the current target, and has no effect on the next boot
$ sudo systemctl isolate multi-user.target
journalctl命令
# 查看所有日志(默认情况下 ,只保存本次启动的日志)
$ sudo journalctl
# 查看内核日志(不显示应用日志):--dmesg 或 -k
$ sudo journalctl -k
# 查看系统本次启动的日志(其中包括了内核日志和各类系统服务的控制台输出):--system 或 -b
$ sudo journalctl -b
$ sudo journalctl -b -0
# 查看上一次启动的日志(需更改设置)
$ sudo journalctl -b -1
# 查看指定服务的日志:--unit 或 -u
$ sudo journalctl -u docker.servcie
# 查看指定服务的日志
$ sudo journalctl /usr/lib/systemd/systemd
# 实时滚动显示最新日志
$ sudo journalctl -f
# 查看指定时间的日志
$ 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"
# 显示尾部的最新 10 行日志:--lines 或 -n
$ sudo journalctl -n
# 显示尾部指定行数的日志
$ sudo journalctl -n 20
# 将最新的日志显示在前面
$ sudo journalctl -r -u docker.service
# 改变输出的格式:--output 或 -o
$ sudo journalctl -r -u docker.service -o json-pretty
# 查看指定进程的日志
$ sudo journalctl _PID=1
# 查看某个路径的脚本的日志
$ sudo journalctl /usr/bin/bash
# 查看指定用户的日志
$ sudo journalctl _UID=33 --since today
# 查看某个 Unit 的日志
$ sudo journalctl -u nginx.service
$ sudo journalctl -u nginx.service --since today
# 实时滚动显示某个 Unit 的最新日志
$ sudo journalctl -u nginx.service -f
# 合并显示多个 Unit 的日志
$ journalctl -u nginx.service -u php-fpm.service --since today
# 查看指定优先级(及其以上级别)的日志,共有 8 级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
$ sudo journalctl -p err -b
# 日志默认分页输出,--no-pager 改为正常的标准输出
$ sudo journalctl --no-pager
# 以 JSON 格式(单行)输出
$ sudo journalctl -b -u nginx.service -o json
# 以 JSON 格式(多行)输出,可读性更好
$ sudo journalctl -b -u nginx.serviceqq
-o json-pretty
# 显示日志占据的硬盘空间
$ sudo journalctl --disk-usage
# 指定日志文件占据的最大空间
$ sudo journalctl --vacuum-size=1G
# 指定日志文件保存多久
$ sudo journalctl --vacuum-time=1years
参考:
https://cloud.tencent.com/developer/article/1516125
https://wiki.archlinux.org/title/Systemd#Running_services_after_the_network_is_up
https://linux.cn/article-5457-1.html
https://access.redhat.com/articles/754933