systemd 服务管理
systemd 是现代 Linux 的初始化系统和服务管理器,以 PID 1 运行,负责管理从开机到关机的所有进程、服务依赖、日志收集和系统状态切换。
核心知识点
| 概念 | 说明 |
|---|
| Unit | systemd 管理的基本单元,包括 service、timer、socket、mount 等 |
| systemctl | 控制 systemd 的主命令行工具 |
| journalctl | 查询 systemd 日志的工具 |
| Unit File | 定义服务行为的配置文件,通常在 /etc/systemd/system/ |
| Target | 一组 Unit 的集合,类似于传统的运行级别 |
| Wants/Requires | 依赖关系:Wants 是弱依赖,Requires 是强依赖 |
| After/Before | 控制启动顺序,不控制依赖关系 |
安装配置
# systemd 是现代 Linux 发行版自带的,不需要额外安装
# 查看 systemd 版本
systemctl --version # 查看当前 systemd 版本号
# 查看系统是否使用 systemd 作为 init 系统
ps -p 1 -o comm= # 如果输出 systemd,说明正在使用
基本使用
服务管理基础命令
# 启动服务(立即运行)
sudo systemctl start nginx # 启动 nginx 服务
# 停止服务(立即停止)
sudo systemctl stop nginx # 停止 nginx 服务
# 重启服务(先停后启)
sudo systemctl restart nginx # 重启 nginx 服务
# 重新加载配置(不中断服务)
sudo systemctl reload nginx # 让 nginx 重新读取配置文件
# 查看服务状态(最常用)
systemctl status nginx # 查看 nginx 当前运行状态、PID、日志
# 设置开机自启
sudo systemctl enable nginx # 开机时自动启动 nginx
# 取消开机自启
sudo systemctl disable nginx # 取消 nginx 的开机自启
# 启动并同时设置开机自启(二合一)
sudo systemctl enable --now nginx # 立即启动 + 设置开机自启
# 查看服务是否在运行
systemctl is-active nginx # 返回 active 或 inactive
# 查看服务是否开机自启
systemctl is-enabled nginx # 返回 enabled 或 disabled
查看系统服务
# 列出所有正在运行的服务
systemctl list-units --type=service # 只显示 service 类型的 unit
# 列出所有已安装的服务(包括未启动的)
systemctl list-unit-files --type=service # 显示所有服务文件及其状态
# 列出失败的服务
systemctl --failed # 查看哪些服务启动失败了
# 查看服务的依赖关系
systemctl list-dependencies nginx # 查看 nginx 依赖哪些服务
高级用法
编写自定义服务文件
# 创建一个自定义服务文件
sudo vim /etc/systemd/system/myapp.service # 在系统服务目录下创建
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Server # 服务描述
Documentation=https://myapp.example.com # 文档链接
After=network.target # 在网络服务启动后再启动
Requires=postgresql.service # 强依赖 PostgreSQL,它挂了我也停
Wants=redis.service # 弱依赖 Redis,它挂了我继续跑
[Service]
Type=simple # 简单类型:启动后就算就绪(最常用)
User=myapp # 以 myapp 用户运行(不用 root,安全)
Group=myapp # 以 myapp 用户组运行
WorkingDirectory=/opt/myapp # 工作目录
ExecStart=/opt/myapp/bin/server --config /etc/myapp/config.yaml # 启动命令(必须用绝对路径)
ExecReload=/bin/kill -HUP $MAINPID # reload 时发送 HUP 信号
Restart=on-failure # 异常退出时自动重启(正常退出不重启)
RestartSec=5 # 重启前等待 5 秒
StartLimitBurst=3 # 连续重启次数限制
StartLimitIntervalSec=60 # 在 60 秒内最多重启 3 次
# 安全加固(2025+ 最佳实践)
PrivateTmp=true # 私有 /tmp 目录,防止被其他进程读取
ProtectSystem=full # 保护 /usr 和 /boot 为只读
ProtectHome=true # 禁止访问 /home 目录
NoNewPrivileges=true # 禁止提升权限
CapabilityBoundingSet=CAP_NET_BIND_SERVICE # 只允许绑定低端口
# 资源限制
LimitNOFILE=65536 # 最大打开文件数
LimitNPROC=4096 # 最大进程数
MemoryMax=2G # 最大内存使用 2GB
CPUQuota=200% # 最多使用 2 个 CPU 核心
# 环境变量
Environment=NODE_ENV=production # 设置环境变量
EnvironmentFile=/etc/myapp/env # 从文件加载环境变量
[Install]
WantedBy=multi-user.target # 在多用户模式下启用(类似运行级别 3)
# 修改服务文件后必须重新加载
sudo systemctl daemon-reload # 让 systemd 重新读取所有 unit 文件
# 启动自定义服务
sudo systemctl enable --now myapp # 启动并设置开机自启
服务模板(管理多个实例)
# /etc/systemd/system/myapp@.service(注意 @ 符号)
[Unit]
Description=My App Instance %i # %i 会被替换为实例名
[Service]
User=myapp # 运行用户
ExecStart=/opt/myapp/bin/server --port %i # %i 替换为传入的参数
Restart=on-failure # 失败时自动重启
[Install]
WantedBy=multi-user.target # 多用户模式
# 启动多个实例,每个监听不同端口
sudo systemctl start myapp@8001 # 启动端口 8001 的实例
sudo systemctl start myapp@8002 # 启动端口 8002 的实例
sudo systemctl start myapp@8003 # 启动端口 8003 的实例
日志管理(journalctl)
# 查看某个服务的日志
journalctl -u nginx # 查看 nginx 的所有日志
# 查看最近的日志(实时跟踪,类似 tail -f)
journalctl -u nginx -f # 实时显示 nginx 新日志
# 查看最近 100 行日志
journalctl -u nginx -n 100 # 只显示最新 100 行
# 查看今天的日志
journalctl -u nginx --since today # 只看今天的
# 查看指定时间段的日志
journalctl -u nginx --since "2025-01-01" --until "2025-01-02" # 时间范围
# 按优先级过滤(err = 错误及以上)
journalctl -u nginx -p err # 只看错误级别的日志
# 查看本次启动的日志
journalctl -u nginx -b # 只看本次开机后的日志
# 查看日志占用磁盘空间
journalctl --disk-usage # 看日志用了多少磁盘
# 清理旧日志(保留最近 7 天)
sudo journalctl --vacuum-time=7d # 删除 7 天前的日志
定时器(替代 crontab)
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily Backup Timer # 每日备份定时器
[Timer]
OnCalendar=*-*-* 02:00:00 # 每天凌晨 2 点执行
Persistent=true # 如果错过了执行时间(比如关机了),开机后补执行
RandomizedDelaySec=300 # 随机延迟 0-300 秒,避免同时执行
[Install]
WantedBy=timers.target # 属于定时器目标
# 查看所有定时器
systemctl list-timers # 列出所有活跃的定时器及下次执行时间
# 启用定时器
sudo systemctl enable --now backup.timer # 启动定时器
常见报错
| 报错 | 原因 | 解决 |
|---|
Failed to start xxx: Unit not found | 服务文件不存在或名字写错 | 检查 /etc/systemd/system/ 下的文件名 |
Main process exited, code=exited, status=203/EXEC | ExecStart 路径错误或没有执行权限 | 检查路径是否正确,用 chmod +x 加权限 |
code=exited, status=217/USER | User 指定的用户不存在 | 用 useradd 创建用户 |
Start request repeated too quickly | 服务频繁崩溃重启超过限制 | 检查应用日志,修复崩溃原因 |
Dependency failed for xxx | 依赖的服务启动失败 | 先修复依赖服务的问题 |
| 修改服务文件后不生效 | 没有执行 daemon-reload | 运行 sudo systemctl daemon-reload |
Address already in use | 端口被其他程序占用 | 用 ss -tlnp \| grep 端口号 查看占用 |
速查表
# === 服务生命周期 ===
systemctl start/stop/restart/reload 服务名 # 启动/停止/重启/重载
systemctl enable/disable 服务名 # 开机自启/取消自启
systemctl enable --now 服务名 # 启动+开机自启二合一
systemctl status 服务名 # 查看状态
systemctl is-active/is-enabled 服务名 # 检查运行/自启状态
# === 查看与排查 ===
systemctl list-units --type=service # 列出运行中的服务
systemctl list-unit-files --type=service # 列出所有服务文件
systemctl --failed # 查看失败的服务
systemctl list-dependencies 服务名 # 查看依赖关系
systemctl cat 服务名 # 查看服务文件内容
# === 日志 ===
journalctl -u 服务名 # 查看服务日志
journalctl -u 服务名 -f # 实时跟踪日志
journalctl -u 服务名 -n 100 # 最新 100 行
journalctl -u 服务名 --since today # 今天的日志
journalctl -u 服务名 -p err # 只看错误
# === 系统管理 ===
systemctl daemon-reload # 重新加载所有 unit 文件
systemctl list-timers # 查看定时器
systemctl isolate multi-user.target # 切换到多用户模式
systemctl isolate graphical.target # 切换到图形界面
systemctl get-default # 查看默认启动目标