linux | 自动化之systemd
linux 中的自动化之systemd
学习总是循序渐进的。
linux 中程序的自动化,包括早期手动启动,查看启动后的日志、分析启动情况,再到后面封装脚本(大致要求启动后检查是否挂了,挂了拉起,没挂跳过)然后加入到定时器任务,再到加入service
关键词:自动化、注册服务、定时器、GUI、CLI
系统管理
systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面
- systemctl
1.1 systemctl 是 systemd 的主命令,用于管理系统
# 重启
systemctl reboot
# 启动进入救援模式
systemctl rescue
1.2 systemd-analyze 用于查看启动耗时
# 查看启动耗时
systemd-analyze
# 查看每个服务启动耗时
systemd-analyze blame
# 显示制定服务的启动流
systemd-analyze critical-chain atd.service
1.3 hostnamectl
# 查看主机信息
hostnamectl
# 设置主机名
sudo hostnamectl set-hostname zhangbuda7788
1.4 timedatectl
# 查看当前时区设置
timedatectl
# 显示所有可用的时区
timedatectl list-timezones
# 设置当前时区
sudo timedatectl set-timezone America/New_York
sudo timedatectl set-time YYYY-MM-DD
sudo timedatectl set-time HH:MM:SS
1.5 查看当前登录用户
# 列出当前的session
loginctl list-sessions
# 列出当前登录用户
loginctl list-users
# 列出显示制定用户信息
loginctl show-user zhangbuda7788
- unit
systemd 管理不同的系统资源,不同的资源统称为 unit 系统->unit->具体的servie
2.1 常见的Unit
# 系统服务
Service unit
# 多个Unit 构成的一个组
Target unit
# 硬件设备
Device unit
# 文件系统的挂载点
Mount unit
# 自动挂载点
Automount Unit
# 文件或路径
Path unit
# 不是由 systemd 启动的外部进程
Scope unit
# 进程组
Slice unit
# 快照,可以切回某个快照
Scope unit
# 进程间通信的 socket
Socket unit
# swap 文件
Swap Unit
# 定时器
Time Unit
2.2 查看系统的所有 Unit
# 列出正在运行的 Unit
systemctl list-unit
# 列出所有的 Unit 包括没有找到配置文件的或者启动失败的
systemctl list-units --all
# 列出所有没有运行的 unit
systemctl list-units --all --state=inactive
# 列出所有加载失败的 Unit
systemctl list-units --failed
# 列出所有正在运行的、类型为 Service 的Unit
systemctl list-units --type=service
- service
3.1 服务的位置
/etc/systemd/system
3.2 查看已经安装的单元文件(unit-file)
systemctl list-unit-files
3.3 查看已经激活的单元任务
systemctl list-units
3.4 服务的具体操作
systemctl is-active/is-failed/is-enabled/enable/disable/start/restart/reload/stop xxx
## 在修改配置文件后,需要重新加载配置文件再启动相关服务
sudo systemctl daemon-reload
## 重启相关服务
sudo systemctl restart xxx
3.5 查看unit 之间的依赖关系
systemctl list-dependencies xxx
查看 包含依赖 target 类型的依赖关系
systemctl list-dependencies -all
3.6 查看配置问价你的状态
# 列出所有配置文件
systemctl list-unit-files
# 列出指定类型的配置文件
## enabled 已建立启动链接
## disabled 没建立启动链接
## static 该配置文件没有 [install] 部分,只能作为其他配置文件的依赖
## masked 该配置文件被禁止建立启动链接
systemctl list-unit-files --type=service
3.7 日志
systemd 管理很多服务,包括系统本身的、后续部署的、以及人工添加的,所以这样可以通过命令 journalctl 命令查看 这几大块的所有服务。
# 查看服务日志
sudo journalctl -u xxx
# 查看实时日志
sudo journalctl -u xxx -f
# 查看近100 行日志
sudo journalctl -u xxx -n 100
# 查看制定时间短的日志
sudo journalctl -u xxx --since '2025-06-12 15:00' --until '2025-06-12 16:00'
3.8 配置文件的格式
配置文件是普通的文本文件,可以用文本编辑器打开。配置文件的区块名和字段名都大小写敏感。每个区块内部是一些等号链接的键值对,键值对的等号两侧不能有空格。
[Unit] 定义 Unit 的元数据,配置 当前要跑的service 与主机系统中的 Unit 内的服务之间的关系
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 运行必须满足的条件,否则会报启动失败
[Service] 用来 Service 的配置 这是具体的 服务。所有,它归属于 Unit 然后 Unit 又归属于整个 Service
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:指定环境变量
[Install] 用来定义如何启动,以及是否开机启动
WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中
RequiredBy:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中
Alias:当前 Unit 可用于启动的别名
Also:当前 Unit 激活(enable)时,会被同时激活的其他 Unit
在 Linux 系统中,systemd target 和传统的 SysV init 启动模式 都是用来控制系统启动时运行哪些服务和程序的机制。但两者在设计理念、结构、管理方式上有本质区别。
Runlevel | 含义 |
---|---|
0 | 关机 |
1 | 单用户模式(维护) |
3 | 多用户模式(无图形) |
5 | 图形界面(X11) |
6 | 重启 |
Target | 等价 Runlevel | 描述 |
---|---|---|
rescue.target |
1 | 单用户模式 |
multi-user.target |
3 | 多用户模式,无图形 |
graphical.target |
5 | 多用户模式,有图形界面 |
reboot.target |
6 | 重启 |
poweroff.target |
0 | 关机 |
default.target |
- | 系统默认启动目标(可配置) |
特性 | SysV Init | systemd target |
---|---|---|
配置文件 | /etc/inittab , /etc/rc*.d/ |
/etc/systemd/system/*.target |
启动机制 | 顺序启动 | 并行启动,基于依赖关系 |
启动级别名称 | runlevel(0~6) | target |
服务控制 | 脚本(/etc/init.d/xxx ) |
单元文件(unit files) |
启动速度 | 较慢 | 更快(并行 + 依赖分析) |
可读性、扩展性 | 差,维护复杂 | 强,结构清晰 |
状态查看命令 | service , chkconfig |
systemctl status ,list-units |
设置默认启动级别 | initdefault in /etc/inittab |
systemctl set-default |
mac 服务
launchctl
launchctl 是 macos 下控制 launchd 的命令行工具
launchd 是 macos 系统初始化和服务管理器(相当于 linux 的 systemd 或 init)
launchctl 允许你家在、启动、停止、卸载系统或用户服务
macos 启动项种类及放置路径
launch Agent 用户级别服务,依附图形登录会话 ~/Library/LaunchAgents/ (不需要sudo)或者 /Library/LaunchAgents/ (需要sudo)
launch Daemon 系统级别服务,在后台独立运行 /Library/LaunchDaemonts/ (需要sudo)
# 启动服务
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/xxx.plist
# 卸载服务
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/xxx.plist
# 查看服务状态
launchctl print gui/$(id -u)/com.xxx.identifier
## 查看服务日志, 一般的会在 配置文件 ~/Library/LaunchAgents/xxx.plist 中配置日志目录 比如 /tmp/frps.log
## 扩展,常见的 mac 日志
# 系统日志
/var/log/system.log
# 崩溃日志
~/Library/Logs/DiagnosticReports
#系统级应用日志
/Library/Logs
补充:
关于 gui/$(id -u)
其中 id -u 返回的是 501 (可以在终端直接执行)
将服务加载到当前用户的图形桌面登录会话中,而不是仅仅在后台或终端运行。
延伸
macos 把用户的图形桌面环境(Finder、Dock、通知中心、菜单栏图标等)当作一个特殊的 【 会话 】
某些服务(托盘图标程序、图像化客户端、桌面通知)必须绑定到这个桌面图形会话中运行,否则不会生效。
这类服务要通过 gui/UID 域注册给桌面环境, UID 可以通过 uid -u 获得。什么是当前用户桌面会话? GUI Session
当登录macos 后看到桌面界面 (Finder、菜单栏、Dock、应用窗口)
是系统中一个完整的用户图形登录会话
运行时对应的 launchd 域是 gui/ 如 gui/501
只有加载到这个会话中的服务,才能与桌面交互(显示界面、通知、托盘图标、剪贴板等)
疑问:
为什么可以 launchctl bootout gui/ ( i d − u ) / c o m . z h a n g b u d a . f r p s 这样退出却不能 l a u n c h c t l b o o t s t r a p g u i / (id -u)/com.zhangbuda.frps 这样退出却不能launchctl bootstrap gui/ (id−u)/com.zhangbuda.frps这样退出却不能launchctlbootstrapgui/(id -u)/com.zhangbuda.frps这样启动,而必须采用 launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.zhangbuda.frps.plist 的方式启动
bootout 支持 domain+label 的方式 也就是 gui/$(id -u)/com.zhangbuda.frps
相应的 launchctl bootstrap 需要提供完成服务 的路径,因为服务还没注册,系统还不知道 该服务的配置。