CnetOS 配置 systemd 服务
自 2010 年 3 月推出以来,人们对 systemd 有不同的看法。 但不可否认的是,systemd 现在几乎存在于所有 Linux 发行版中!
当然,有些 Linux 发行版明确宣传使用 systemd 以外的其他初始化系统,但这种情况非常少见。 Ubuntu、Fedora、RHEL、Debian、Pop!_OS、openSUSE、Arch——所有这些都默认附带 systemd。
由于 systemd 的使用如此广泛,因此值得一看并学习如何创建 systemd 服务。
什么是 systemd 服务?
简单地说,服务就是一个根据特定情况启动或停止的 后台进程
。 您不需要手动启动和/或停止它。 systemd 服务文件
是一种以 systemd 能够解析和理解它的格式编写的文件,稍后可以执行您告诉它执行的操作。
从技术上讲,我所说的 systemd 服务文件
实际上称为 systemd 单元
文件,但由于本教程是关于创建服务的,因此我将继续将其称为 systemd 服务文件
。
systemd 服务文件的基本结构
systemd 服务文件包含三个重要且必要的部分。 它们是 [Unit]、[Service] 和 [Install] 部分。 systemd 服务文件的扩展名是 .service,我们使用井号 (#) 表示单行注释。
Unit
此部分中使用的参数不仅限于 service 类型的 unit,对其它类型 unit 也是通用的,有关这些参数及其说明的完整列表,可运行命令 man systemd.unit
注意:在 [unit] 块中的每个参数后都可以指定一个以空格分隔的列表
- Description:当前 unit 的描述
- Documentation:文档地址,仅接受类型为:http://、https://、file:、info:、man: 的URI
- Requires:表示本 unit 与其它 unit 之间存在强依赖关系,如果本 unit 被激活,此处列出的 unit 也会被激活,如果其中一个依赖的 unit 无法激活,systemd 都不会启动本 unit
- Wants:与 Requires 类似,区别在于如果依赖的 unit 启动失败,不影响本 unit 的继续运行【推荐使用】
- After:表示本 unit 应该在某服务之后启动,只涉及启动顺序,不涉及依赖关系。
- Before:表示本 unit 应该在某服务之前启动,只涉及启动顺序,不涉及依赖关系。
- BindsTo:与 Requires 类似,当指定的 unit 停止时,也会导致本 unit 停止
- PartOf:与 Requires 类似,当指定的 unit 停止或重启时,也会导致本 unit 停止或重启
- Conflicts:如果指定的 unit 正在运行,将导致本 unit 无法运行
- OnFailure:当本 unit 进入故障状态时,激活指定的 unit
Service
service专有参数
只有 service 类型的 unit 才有这些参数,参数完整列表请访问 man systemd.service
或 man 5 systemd.service
-
Type:配置该服务单元的进程启动类型。 simple、fork、oneshot、dbus、notify 或idle 之一。
- simple:期望配置了
ExecStart=
的进程是服务的主进程。 没有配置Type有配置ExecStart默认是 simple - forking:使用 ExecStart= 配置的进程将调用 fork() 作为其启动的一部分。 当启动完成并且所有通信通道都建立后,父进程预计将退出。 子进程继续作为主守护进程运行。 这是传统 UNIX 守护程序的行为。 如果使用此设置,建议同时使用 PIDFile= 选项,以便 systemd 可以识别守护进程的主进程。 一旦父进程退出,systemd 将继续启动后续单元。
- oneshot:与 simple 类似,但是预计该进程必须在 systemd 启动后续单元之前退出。 RemainAfterExit= 对于此类服务特别有用。 如果未指定 Type= 或 ExecStart=,则这是隐含的默认值。
- dbus:类似于 simple; 然而,守护进程需要在 D-Bus 总线上获取一个名称,如 BusName= 配置的那样。 获取 D-Bus 总线名称后,systemd 将继续启动后续单元。 配置此选项的服务单元隐式获得对 dbus.socket 单元的依赖。 如果指定 BusName=,则此类型是默认类型。
- notify:与simple类似; 但是,预计守护程序在完成启动后会通过 sd_notify(3) 或等效调用发送通知消息。 发送此通知消息后,systemd 将继续启动后续单元。 如果使用此选项,则应设置 NotifyAccess=(见下文)以打开对 systemd 提供的通知套接字的访问。 如果未设置 NotifyAccess=,它将隐式设置为 main。 请注意,如果与 PrivateNetwork=yes 结合使用,目前 Type=notify 将不起作用。
- idle:与 simple 非常相似; 但是,服务二进制文件的实际执行会延迟到所有作业都已分派为止。 这可用于避免 shell 服务的输出与控制台上的状态输出交错。
常见到的类型有
simple
、forking
和notify
- simple:期望配置了
-
ExecStartPre/ExecStartPost::分别在 ExecStart= 中的命令之前或之后执行的附加命令。 语法与 ExecStart= 相同,不同之处在于允许多个命令行,并且命令按顺序一个接一个地执行。
请注意,ExecStartPre= 不能用于启动长时间运行的进程。 通过 ExecStartPre= 调用的进程派生的所有进程都将在下一个服务进程运行之前被终止。
-
ExecStart: 启动此服务时执行的带有参数的命令。
-
ExecReload: 执行以触发服务中的配置重新加载的命令。
-
ExecStop: 执行命令以停止通过 ExecStop= 停止的服务。运行此选项中配置的命令后,将根据 KillMode= 设置终止服务剩余的所有进程(请参阅
man systemd.kill
)。 -
ExecStopPost: 服务停止后执行的其他命令。 这包括使用 ExecStop= 中配置的命令、服务未定义任何 ExecStop= 或服务意外退出的情况。
-
Restart: 配置当服务进程退出、被终止或达到超时时是否应重新启动服务。当进程死亡是 systemd 操作(例如服务停止或重启)的结果时,服务将不会重新启动。 超时包括错过看门狗“keep-alive ping”最后期限和服务启动、重新加载和停止操作超时。
-
RestartSec: 配置重启服务前的休眠时间(使用 Restart= 配置)。 采用以秒为单位的无单位值,或时间跨度值,例如“5 分钟 20 秒”。 默认为 100 毫秒。
-
TimeoutSec: 将 TimeoutStartSec= 和 TimeoutStopSec= 配置为指定值的简写。
-
PIDFile: 主进程的PID号,通常与
Type=forking
使用请注意,守护进程应在完成初始化之前写入该文件,否则 systemd 可能会尝试在该文件存在之前读取该文件。
进程相关参数
services, sockets, mount points, swap 的单元配置文件共享定义生成进程的执行环境的配置选项子集。(请参阅 man 5 systemd.exec
)
- Environment:设置进程环境变量,参数后都可以指定一个以空格分隔的列表
- EnvironmentFile:进程环境变量文件
- WorkingDirectory:采用绝对目录路径。 设置已执行进程的工作目录。 如果未设置,则当 systemd 作为系统实例运行时默认为根目录,如果作为用户运行则默认为相应用户的主目录。
- User、Group:启动服务的用户名和租户名
- UMask:控制文件模式创建掩码。 采用八进制表示法的访问模式。 详细信息请参见 umask(2)。 默认为 0022。
- LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME=: 限制各类资源信息
进程kill参数
- KillMode: 指定如何终止该单元的进程。选择 control-group, process, mixed, none. 默认是 control-group。(请参阅
man systemd.kill
)- control-group: 该单元控制组中的所有剩余进程将在单元停止时被杀死(对于服务:在执行停止命令后,如 ExecStop= 所配置),
- process: 如果设置为进程,则仅杀死主进程本身。
- mixed: SIGTERM 信号将发送到主进程,而后续的 SIGKILL 信号将发送到单元控制组的所有剩余进程。
- none: 不会终止任何进程。 在这种情况下,在单元停止时只会执行停止命令,否则不会杀死任何进程。 停止后仍然存活的进程留在它们的控制组中,并且控制组在停止后继续存在,除非它是空的。
Install
[Install] 定义了 unit 的安装信息,此部分配置仅在 systemctl enable 或 systemctl disable 时使用,在 unit 运行时不解释此部分,相当于是配置如何开机启动
此部分中使用的参数不仅限于service类型的unit,对其它类型的 unit也是通用的,有关这些参数及其说明的完整列表,可运行命令 man systemd.unit
- Alias:当前 unit 可用于启动的别名,此处列出的名称必须与服务文件名具有相同的后缀(即类型),在执行 systemctl enable 时将创建从这些名称到 unit 文件名的符号链接
- RequiredBy:表示该服务所在的Target,它的值是一个或多个Target,当 systemctl enable 时 unit 符号链接会放入 /etc/systemd/system 目录下面以 Target名 + .required 后缀构成的子目录中
- WantedBy:表示该服务所在的Target,它的值是一个或多个Target,当前 systemctl enable 时 unit符号链接会放入 /etc/systemd/system 目录下面以 Target名 + .wants 后缀构成的子目录中
- Also:当 systemctl enable 或 systemctl disable 时会同时 enable 和 disable 的其它 unit 列表
Target含义
Target的含义是服务组,表示一组服务 WantedBy=multi-user.target 指的是,unit 所在的 Target 是multi-user.target(多用户模式)
这个设置非常重要,因为执行systemctl enable 是会将 unit 链接到 /etc/systemd/system/multi-user.target.wants目录之中,实现开机启动的功能
示例
zookeeper
cat <<'EOF' | sudo tee /usr/lib/systemd/system/zookeeper.service >> /dev/null
[Unit]
Description=Zookeeper Server
Documentation=https://zookeeper.apache.org/doc/
Wants=network.service
After=network.service
[Service]
# zookeeper启动属于fork进程启动,这里务必配置forking
Type=forking
# 配置java环境,zookeeper运行日志目录,zookeeper服务运行pid号
Environment=JAVA_HOME=/opt/jdk ZOO_LOG_DIR=/app/zookeeper/logs ZOOPIDFILE=/app/zookeeper/zookeeper.pid
# 启动用户为ops
User=ops
# 启动zookeeper命令
ExecStart=/opt/zookeeper/bin/zkServer.sh start /app/zookeeper/conf/zoo.cfg
# 停止zookeeper命令
ExecStop=/opt/zookeeper/bin/zkServer.sh stop /app/zookeeper/conf/zoo.cfg
# 服务生成的pid文件
PIDFile=/app/zookeeper/zookeeper.pid
# 仅当服务是fail状态重启
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
traefik
cat <<'EOF' | sudo tee /usr/lib/systemd/system/traefik.service >> /dev/null
[Unit]
Description=traefik Server
Documentation=https://doc.traefik.io/traefik/
Wants=network.service
After=network.service
[Service]
Type=simple
ExecStart=/app/traefik/traefik --configfile /app/traefik/config/traefik.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?