【Linux】systemd 服务管理详解
目录
引言
一、systemd简介
二、systemd 服务单元
2.1 服务单元文件(.service 文件)
2.1.1 文件位置
2.1.2 文件命名约定
2.2 服务单元文件结构
核心部分与常用指令
三、常用 systemctl 命令
3.1 服务状态与控制
3.2 服务启用与禁用(开机自启)
3.3 查看服务列表与日志
3.4 其他重要命令
四、自定义 systemd 服务示例
4.1. 创建服务用户(推荐)
4.2 编写服务文件
4.3 启用并启动服务
五、注意事项
引言
在现代 Linux 系统中,systemd 已经成为绝大多数主流发行版(如 Ubuntu, CentOS/RHEL, Debian, Fedora 等)默认的系统和服务管理器。它取代了传统的 SysVinit 和 Upstart,带来了更快的启动速度、更强大的依赖管理、更完善的日志记录和更灵活的服务控制能力。
一、systemd简介
systemd 是一个 Linux 系统的系统和服务管理器。它作为 PID 1 进程启动,是整个用户空间进程的“祖先进程”。它的主要职责包括:
- 系统初始化: 并行启动系统服务,显著加快启动速度。
- 服务管理: 启动、停止、重启、监控和管理各种系统服务(如 Web 服务器、数据库、自定义应用)。
- 依赖管理: 自动处理服务之间的依赖关系,确保服务按正确顺序启动。
- 资源管理: 集成 cgroups,更好地管理和隔离服务资源。
- 日志管理: 提供
journald服务,集中管理结构化日志。 - 设备管理: 与
udev集成,管理硬件设备的热插拔。 - 定时任务: 提供
timer单元,作为cron的现代化替代。
本文只聚焦于服务管理。
二、systemd 服务单元
2.1 服务单元文件(.service 文件)
每个由 systemd 管理的服务都由一个配置文件定义,通常以 .service 结尾。
这些文件定义了服务如何启动、停止、重启以及其运行环境。
2.1.1 文件位置
- 系统服务:
/usr/lib/systemd/system/: 由软件包安装的默认服务文件。不建议直接修改,因为更新软件包时可能被覆盖。/etc/systemd/system/: 系统管理员创建或覆盖默认配置的首选位置。优先级高于/usr/lib/systemd/system/。
- 用户服务:
~/.config/systemd/user/或/usr/lib/systemd/user/(用于用户级别的服务)。
2.1.2 文件命名约定
服务文件通常命名为 <service-name>.service。
例如:
nginx.servicemysql.servicemyapp.service
在使用 systemctl 命令时,.service 后缀通常可以省略。
2.2 服务单元文件结构
一个 .service 文件是 INI 格式的文本文件,包含多个 [Section],每个部分包含键值对。
核心部分与常用指令
[Unit]
# 通用元数据和依赖关系
Description=My Custom Application Service
Documentation=https://example.com/myapp/docs
After=network.target syslog.target
# Before=other-service.service
# Requires=network.target mysql.service
# Wants=network.target
# Conflicts=old-app.service
Description=: 服务的描述。Documentation=: 指向服务文档的链接。After=: 指定本服务在哪些目标(target)或其他服务之后启动。不表示依赖,仅控制顺序。常用network.target表示网络就绪。Before=: 指定本服务在哪些目标或其他服务之前启动。Requires=: 强依赖。如果列出的服务启动失败,本服务也会启动失败。Wants=: 弱依赖。推荐启动列出的服务,但即使它们失败,本服务仍会尝试启动。比Requires=更常用。Conflicts=: 冲突关系。如果列出的服务正在运行,本服务不能启动,反之亦然。
[Service]
# 服务的具体执行和行为
Type=simple
ExecStart=/usr/bin/myapp --config /etc/myapp/config.yaml
# ExecStartPre=/bin/sleep 10 # 启动前执行的命令
# ExecStartPost=/bin/echo "Service started"
# ExecStop=/usr/bin/myapp --stop
# ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
TimeoutSec=30
User=myappuser
Group=myappgroup
WorkingDirectory=/var/lib/myapp
# Environment=ENV_VAR=value
# EnvironmentFile=/etc/myapp/environment
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
# KillMode=process
# KillSignal=SIGTERM
# SuccessExitStatus=0 143
Type=: 最关键的指令之一,定义了服务的启动类型:
simple(默认):systemd认为ExecStart启动的进程就是主进程。适用于前台运行的守护进程。forking: 适用于传统的守护进程(daemon),它们会 fork 并让父进程退出。systemd会跟踪 fork 出的子进程。通常需要PIDFile=指定 PID 文件路径。oneshot: 一次性任务。systemd会等待命令执行完毕才继续。常用于脚本或初始化任务。配合RemainAfterExit=yes使用,表示服务在命令执行后仍被视为“激活”状态。dbus: 服务在获取一个 D-Bus 名称后才被视为启动成功。notify: 服务通过sd_notify()调用通知systemd启动完成。需要服务本身支持。idle: 类似simple,但执行延迟到所有活动完成。ExecStart=: 必需。指定启动服务时执行的命令及其参数。只能有一个ExecStart=指令(除非Type=oneshot)。ExecStartPre=/ExecStartPost=: 在ExecStart之前/之后执行的命令。ExecStop=: 指定停止服务时执行的命令。如果未设置,systemd会发送SIGTERM信号。ExecReload=: 指定重新加载服务配置时执行的命令(如systemctl reload)。Restart=: 定义服务进程退出后是否重启:
no(默认): 不重启。on-success: 仅在正常退出(退出码 0)或被systemd重启时重启。on-failure: 在非正常退出(非零退出码)、被信号终止(非SIGKILL)、超时或被看门狗终止时重启。最常用。on-abnormal: 在被信号终止、超时或看门狗终止时重启。on-abort: 在被信号终止或看门狗终止时重启。always: 无论退出原因如何都重启。RestartSec=: 重启前等待的秒数(默认 100ms)。TimeoutSec=: 启动、停止、重启操作的超时时间(秒)。可被TimeoutStartSec=,TimeoutStopSec=覆盖。User=/Group=: 以指定的用户和组身份运行服务进程。强烈推荐为服务创建专用用户。WorkingDirectory=: 设置服务进程的工作目录。Environment=: 设置环境变量。可多次使用。EnvironmentFile=: 从文件中读取环境变量(每行KEY=value)。StandardOutput=/StandardError=: 定义标准输出和错误的处理方式。journal(默认) 发送到journald;syslog发送到 syslog;null丢弃;tty输出到控制台。SyslogIdentifier=: 在日志中使用的标识符(替代进程名)。KillMode=: 定义停止服务时如何发送信号:
control-group(默认): 向服务的 cgroup 中所有进程发送信号。process: 仅向主进程(ExecStart启动的)发送信号。mixed: 先发送SIGTERM,等待超时后发送SIGKILL。none: 不发送信号。KillSignal=: 停止服务时发送的信号(默认SIGTERM)。SuccessExitStatus=: 指定哪些退出码被视为“成功”(不影响Restart=on-failure的判断)。
[Install]
# 定义服务如何被启用(enable)
WantedBy=multi-user.target
# Also=other-service.service
# RequiredBy=other-service.service
WantedBy=: 最常用。当启用(systemctl enable)此服务时,会在指定的 target 的.wants/目录下创建一个指向此服务文件的符号链接。例如WantedBy=multi-user.target表示服务在多用户模式下被“需要”。RequiredBy=: 类似WantedBy=,但创建的是.requires/链接,表示强依赖。Also=: 当此服务被启用/禁用时,同时启用/禁用列出的服务。
三、常用 systemctl 命令
systemctl 是管理 systemd 服务的主要命令行工具。
3.1 服务状态与控制
| 命令 | 说明 |
|---|---|
systemctl status <service> | 查看服务的详细状态(运行状态、PID、日志片段等)。 |
systemctl start <service> | 启动服务。 |
systemctl stop <service> | 停止服务。 |
systemctl restart <service> | 重启服务。 |
systemctl reload <service> | 重新加载服务配置(不中断服务)。 |
systemctl try-restart <service> | 如果服务正在运行,则重启它。 |
systemctl kill <service> | 向服务进程发送信号(可指定信号)。 |
systemctl is-active <service> | 检查服务是否处于 active (running) 状态。 |
systemctl is-enabled <service> | 检查服务是否已启用(开机自启)。 |
3.2 服务启用与禁用(开机自启)
| 命令 | 说明 |
|---|---|
systemctl enable <service> | 启用服务,创建符号链接,使其在下次启动时自动运行。 |
systemctl disable <service> | 禁用服务,删除符号链接,下次启动时不再自动运行。 |
systemctl reenable <service> | 先禁用再启用服务,用于刷新链接。 |
systemctl preset <service> | 根据预设规则(/usr/lib/systemd/system-preset/)启用/禁用服务。 |
3.3 查看服务列表与日志
| 命令 | 说明 |
|---|---|
systemctl list-units --type=service | 列出所有已加载的服务及其状态。 |
systemctl list-units --type=service --state=active | 仅列出正在运行的服务。 |
systemctl list-unit-files --type=service | 列出所有服务单元文件及其启用状态(enabled, disabled, static, masked)。 |
journalctl -u <service> | 查看指定服务的完整日志。 |
journalctl -u <service> -f | 实时跟踪(-f)指定服务的日志。 |
journalctl -u <service> --since "2023-10-27 10:00" | 查看指定时间范围内的日志。 |
journalctl -u <service> -p err | 查看指定服务的错误级别日志。 |
3.4 其他重要命令
| 命令 | 说明 |
|---|---|
systemctl daemon-reload | 重要! 当修改了服务文件后,必须运行此命令重新加载 systemd 配置。否则 systemctl 命令可能找不到新服务或使用旧配置。 |
systemctl cat <service> | 显示服务单元文件的完整内容(包括片段)。 |
systemctl show <service> | 显示服务的详细属性(所有配置项的当前值)。 |
systemctl list-dependencies <service> | 列出服务的依赖关系。 |
四、自定义 systemd 服务示例
创建一个名为 myapp 的 Python 脚本,位于 /opt/myapp/myapp.py,希望它作为服务运行。
4.1. 创建服务用户(推荐)
sudo useradd -r -s /bin/false myappuser
4.2 编写服务文件
创建文件 /etc/systemd/system/myapp.service:
[Unit]
Description=My Awesome Python Application
After=network.target
Wants=network.target[Service]
Type=simple
User=myappuser
Group=myappuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/myapp.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp[Install]
WantedBy=multi-user.target
4.3 启用并启动服务
# 重新加载 systemd 配置以识别新服务
sudo systemctl daemon-reload# 启用服务(开机自启)
sudo systemctl enable myapp.service# 启动服务
sudo systemctl start myapp.service# 检查状态
sudo systemctl status myapp.service# 查看日志
sudo journalctl -u myapp.service -f
五、注意事项
- 使用专用用户: 为每个服务创建专用的系统用户,避免使用
root运行服务,提升安全性。 - 明确
Type: 正确设置Type对于systemd正确监控服务至关重要。对于大多数现代应用,simple是合适的。 - 合理设置
Restart:on-failure通常是生产环境的最佳选择,防止服务因崩溃而长时间离线,同时避免因配置错误导致无限重启循环。 - 日志重定向: 将
StandardOutput和StandardError设置为journal,利用journald的强大日志功能。 - 修改后
daemon-reload: 切记在修改任何.service文件后,必须运行sudo systemctl daemon-reload。 - 测试配置: 使用
systemctl cat <service>和systemctl show <service>验证配置是否被正确加载。 - 避免直接修改
/usr/lib/下的文件: 将自定义或覆盖配置放在/etc/systemd/system/目录下。 - 处理依赖: 清晰地定义
After和Wants/Requires,确保服务在依赖项(如网络、数据库)就绪后才启动。 - 监控与告警: 结合
systemctl is-active和日志监控工具,建立服务健康检查和告警机制。
