在 Ubuntu 15.04 之后,systemd 取代了传统的 SysV init,成为系统默认的初始化系统与服务管理器。作为 Linux 运维人员,深入理解 systemd 的 Unit 文件结构、开机自启机制以及故障诊断方法,是从”会用命令”走向”能管住服务”的关键一步。今天我们将系统梳理 systemd 服务管理的核心知识,让你在面对服务启动失败、依赖混乱、开机自启失效等问题时,能够快速定位并解决。

核心概念:systemd 与 Unit 文件
systemd 不仅是 PID 1 的初始化进程,更是一整套系统管理工具集。它通过 systemctl 命令与用户交互,用”Unit(单元)”作为统一抽象来描述需要管理的资源。Unit 类型主要包括:
service:描述一个系统服务,是最常用的类型;socket:封装本地 IPC 或网络套接字,支持按需启动;target:一组 Unit 的聚合目标,类似传统运行级别;timer:基于时间的定时任务单元,可替代部分 cron;mount与automount:管理挂载点;slice:对进程组进行资源控制的分片单元。
每一个 Unit 都由一个 Unit 文件定义。这些文件按优先级分布在三个目录:/lib/systemd/system(发行版自带)、/etc/systemd/system(管理员自定义,优先级最高)、/run/systemd/system(运行时临时生成)。我们日常编写自定义服务时,统一放在 /etc/systemd/system 下。
实战步骤:编写并管理自定义服务
1. 认识 Unit 文件结构
一个典型的 service Unit 文件由 [Unit]、[Service]、[Install] 三个段落组成。以部署一个 Python Web 应用为例:
[Unit]
Description=My Python Web App
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5
Environment=APP_ENV=production
EnvironmentFile=-/etc/myapp/myapp.env
[Install]
WantedBy=multi-user.target
其中 [Unit] 段描述元数据与依赖关系,After/Before 控制启动顺序,Wants/Requires 控制依赖强弱;[Service] 段是核心,Type 决定 systemd 如何判断服务是否启动成功;[Install] 段通过 WantedBy 声明在哪个 target 下创建软链接,从而实现开机自启。
2. 创建并加载服务
把上面的内容保存为 /etc/systemd/system/myapp.service,然后执行加载与启动:
sudo systemctl daemon-reload # 重载 systemd 配置
sudo systemctl enable myapp # 设置开机自启
sudo systemctl start myapp # 立即启动服务
sudo systemctl status myapp # 查看运行状态
enable 与 start 的区别要牢记:start 只是本次启动,enable 才会在 /etc/systemd/system/multi-user.target.wants/ 下创建指向该 Unit 的软链接,让服务随系统开机自动运行。
3. 理解 Service Type 的差异
Type 的取值直接影响 systemd 对”服务已就绪”的判断,是排障时的重点:
| Type | 含义 |
|---|---|
| simple | 默认值,认为启动 ExecStart 后服务即就绪,进程需长期驻留 |
| forking | ExecStart 启动后父进程 fork 出子进程并退出,systemd 等待其退出 |
| oneshot | 执行完即退出,常用于一次性初始化任务 |
| notify | 服务就绪后通过 sd_notify 通知 systemd |
| idle | 延迟到没有其他任务时再启动 |
若把守护进程写成 Type=simple 却预期其 fork 后台,systemd 会误判服务已退出,导致不断重启,这是最常见的配置错误之一。
常用 systemctl 命令速查
日常管理离不开下面这组命令,建议形成肌肉记忆:
sudo systemctl start nginx # 启动
sudo systemctl stop nginx # 停止
sudo systemctl restart nginx # 重启
sudo systemctl reload nginx # 热重载配置(服务需支持)
sudo systemctl enable nginx # 开机自启
sudo systemctl disable nginx # 取消开机自启
sudo systemctl status nginx # 查看状态
sudo systemctl list-units --type=service --state=running # 列出运行中的服务
sudo systemctl list-unit-files --type=service # 查看所有服务的自启状态
sudo systemctl is-enabled nginx # 检查某服务是否已启用
sudo journalctl -u nginx -f # 实时查看该服务日志
故障诊断:服务启动失败的排查思路
第一步:看状态与错误信息
当服务无法启动,先运行 systemctl status,它会显示服务的状态、主 PID 以及最近几行日志:
sudo systemctl status myapp
输出中的 Active: failed 与 Process: ... (code=exited, status=...) 是重要线索。紧接着用 journalctl 查看完整日志,这是 systemd 服务排障的核心工具:
sudo journalctl -u myapp -n 50 --no-pager
第二步:检查 Unit 文件语法
语法错误会直接导致加载失败。systemd 提供了专用校验命令:
sudo systemd-analyze verify /etc/systemd/system/myapp.service
该命令会指出 Unit 文件中缺失的指令、拼写错误以及依赖不完整等问题。
第三步:检查权限、路径与依赖
很多启动失败并非 Unit 本身的问题,而是:
User/Group指定的账号不存在;WorkingDirectory或ExecStart中的路径不存在或不可执行;EnvironmentFile中缺少必需的环境变量;- 依赖的其他服务没有在
After/Requires中正确声明。
可以用 systemd-analyze 分析整体启动耗时与依赖关系,找出瓶颈:
sudo systemd-analyze blame # 按耗时排序显示各服务启动时间
sudo systemd-analyze critical-chain myapp.service # 查看依赖链
常见问题
Q1:enable 了服务但开机没启动怎么办?
先用 systemctl is-enabled myapp 确认状态为 enabled;再检查 [Install] 段的 WantedBy 目标是否与实际运行的 target 匹配。若服务依赖网络,还需加上 After=network-online.target 与 Wants=network-online.target,否则可能在网络未就绪时启动失败。
Q2:修改 Unit 文件后不生效?
每次修改 /etc/systemd/system/ 下的 Unit 文件后,必须先执行 sudo systemctl daemon-reload 让 systemd 重新读取,否则改动不会生效。
Q3:服务反复重启(Restart=on-failure)导致日志爆炸怎么办?
先停掉服务,用 journalctl -u myapp -n 200 定位真实错误根因,而不是放任其无限重启。可以在 [Service] 段增加 StartLimitIntervalSec 与 StartLimitBurst 限制重启频率,避免系统资源被耗尽。
总结
systemd 服务管理是 Ubuntu 运维的核心基本功。掌握 Unit 文件的三大段落、systemctl 的常用命令,以及”状态→日志→语法→环境”的四步排障思路,你就能从容应对绝大多数服务管理场景。今天的内容也为后续定时任务(systemd timer)、容器服务管理(Docker 的 systemd 集成)等主题打下了坚实基础。
下期预告:第 9 天我们将进入「进程管理与性能监控」,学习 ps、top、htop 的使用,以及如何分析系统负载、定位高 CPU 与内存消耗的进程,敬请期待。















暂无评论内容