目录
本教程将由浅入深的介绍 linux 中 Systemd 的知识和相关使用(同时也方便自己后续查阅)
【三】如何自定义 Systemd 服务
2.1 Systemd 是如何定义和管理服务的
Systemd 是通过配置文件来定义服务的,Systemd 会按照如下的目录顺序查找服务配置
/etc/systemd/system/
:自定义或修改后的服务文件/run/systemd/system/
:运行时服务文件/usr/lib/systemd/system/
:软件包提供的服务文件
(这也意味着,假设系统中原先定义了一个服务,可以通过在 /etc/systemd/system/
重写该服务的定义,覆盖原服务)
命令 systemctl daemon-reload
当修改了 Systemd 的配置文件后,需要执行 systemctl daemon-reload
来加载配置文件变更,配置文件的修改才能生效。
2.2 理解服务配置文件
下面将通过一个具体的配置文件的例子,让读者对 systemd 配置文件有一个直观地感受。
注意,这个例子并不是一个面面俱到的手册,只是方便理解的例子。
[Unit]
Description=My Awesome Service
Documentation=https://example.com/docs
After=network.target
Requires=postgresql.service
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/myservice --config /etc/myapp/config.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStartSec=30s
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
[Unit] 部分:元数据和依赖关系定义
- Description:人类可读的服务描述
- Documentation:包含服务文档的 URL 或手册页。
- After:定义执行顺序(但不创建依赖关系)
- Requires:硬依赖 - 如果此项失败,服务将无法启动。
- Wants:软依赖 - 即使此项失败,服务也将启动。
其中 After、Requires 和 Wants 都支持多个选项,使用空格分隔开。同时,他们后面的选项可以是任意的 Unit。
这里我觉得比较难以理解的是 After 和 Wants 的区别。After 指定启动顺序但不设定依赖,意思是如果只设定 After 某个服务,根本就不会触发这个服务的启动行为。这里可以举一个例子:假设你的服务依赖于 redis.service
- 单独使用 Wants=redis.service:Systemd 会尝试启动 redis.service,但你的服务可能在 redis.service 完全启动之前就启动了,导致失败。
- 单独使用 After=redis.service:如果 redis.service 未被其他服务启动(例如没有 Wants 或 Requires),则 redis.service 根本不会启动,After 只是空谈顺序。
[Service] 部分:运行时行为配置
- Type:systemd 如何确定服务是否成功启动
- simple: 默认,服务启动命令所启动的主进程启动成功,那么就认为服务已经启动了
- forking:主进程 fork 出子进程,父进程退出。systemd 依赖 PIDFile 配置判断子进程是否启动成功(可以配置多个)。若未指定 PIDFile,systemd 会使用超时机制来判定服务是否启动成功。
- oneshot:服务在完成任务后退出,systemd 将等待程序执行完成,根据退出时的状态码判定服务是否运行成功。
- notify: 服务在准备就绪时向 Systemd 发出 ready 信号
- dbus:systemd 检测服务在 D-Bus 上注册了自己
- User/Group:以这个用户/组而不是以 root 用户运行服务
- WorkingDirectory:服务的工作目录,主要作用是明确文件路径的解析、确保服务的一致性、简化配置和管理等
- ExecStart:用于启动服务的命令
- ExecReload: 重新加载配置的命令
- Restart:何时自动重新启动服务
- Options:no、on-success、on-failure、on-abnormal、on-watchdog、on-abort、always
- RestartSec:重新启动前需等待多长时间
- Environment:服务的环境变量
[Install] 部分:启动时集成。
- WantedBy: 哪个目标需要此服务,常见目标如下
- multi-user.target:正常多用户系统。
- graphical.target:图形界面。
- network-online.target:当网络完全启动时。
2.3 自定义服务案例
下面让我们实际创建一个 systemd 管理的服务!
我们可以设想这样一个功能
一个 python 脚本每隔 1s 向一个服务发送心跳,这样我们就可以感知到集群每台机器的存活状态。脚本如下:
import requests
import time
API = '...' # 某个心跳链接地址
MACHINE_ID = 'xxxxxxx' # 可以是写死的,也可以从环境变量读取
def heartbeat():
while True:
try:
res = requests.post(API, json={'id': MACHINE_ID})
print(res.status_code)
except Exception as e:
print('Error: ' , e)
finally:
time.sleep(1)
if __name__ == "__main__":
heartbeat()
步骤 1:准备工作(非必须)
为服务创建单独的用户,这样可以提升安全性和可维护性
sudo useradd -r -s /bin/false heartbeat-reporter
-r
选项表示创建一个系统用户(系统用户通常用于运行特定服务,其默认设置和普通用户有所不同)-s /bin/false
选项指定该用户的默认 shell 为 /bin/false ,意味着该用户不能登录系统进行交互式操作,适合用于仅运行特定服务的场景
让该用户可以访问工作空间
sudo chown -R heartbeat-reporter:heartbeat-reporter /opt/custom-heartbeat
步骤 2:创建服务文件
编辑 /etc/systemd/system/custom-heartbeat.service
[Unit]
Description=Custom heartbeat
After=network.target
[Service]
Type=simple
User=heartbeat-reporter
Group=heartbeat-reporter
WorkingDirectory=/opt/custom-heartbeat
ExecStart=python /opt/custom-heartbeat/run.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=custom-heartbeat
Environment=REPORT_API=http://....
[Install]
WantedBy=multi-user.target
步骤 3:重新加载配置文件并运行
# 让 systemd 重新加载配置文件
sudo systemctl daemon-reload
# 将 custom-heartbeat.service 配置为开机启动,并立即启动(--now)
sudo systemctl enable --now custom-heartbeat.service
通过以上步骤,就在 linux 系统中定义了一个自定义的服务,并配置了开机启动。
2.4 一些有用的配置
环境变量
[Service]
# 设置 1 个环境变量
Environment=NODE_ENV=production
# 同时设置多个环境变量
Environment="NODE_ENV=production" "PORT=3000" "DEBUG=false"
# 指定环境变量文件
EnvironmentFile=/etc/myapp/env
资源限制
[Service]
# CPU 使用率限制
CPUQuota=50%
# 限制内存使用
MemoryLimit=512M
# 限制进程或者线程数量
LimitNPROC=100
# 设置磁盘 io 优先级
IOSchedulingClass=best-effort
IOSchedulingPriority=5
当然,随着大语言模型的出现,这些配置没有必要死记硬背。
但是还是需要了解这些机制,否则就好像 AI 辅助编程,如果只依赖 AI 而完全没有你自己的知识和理解,你的工作最后会变成一团难以解开的乱麻!