Systemd 入门实战:手写 unit 文件,优雅管理你的服务
现在稍微新一点的 Linux 发行版,开机后的第一个进程(PID 1)几乎都是 systemd。从 CentOS 7、Ubuntu 16.04、Debian 8 开始,它全面接管了传统 SysV init 的工作。你每天随手敲的 systemctl start nginx、systemctl enable docker,背后都是它在干活。理解 systemd,是从“会用 Linux”走向“能运维 Linux”的关键一步。
一、systemd 到底是什么
传统 SysV init 是串行启动服务的:一堆脚本按编号顺序执行,前一个慢了,后面全都得等着。systemd 换了一套思路:
- 并行启动:根据依赖关系图,同时启动互不依赖的服务,开机更快;
- 按需激活:socket、path、timer 等多种触发方式,服务不用常驻也能响应请求;
- cgroup 统一管理:每个服务都在自己的 cgroup 里,资源隔离、进程追踪更干净,再也不会出现“服务停了但子进程还在跑”的尴尬;
- 声明式配置:服务怎么启、挂了怎么办、依赖谁,全写在一个 unit 文件里,一目了然。
二、核心概念:unit
systemd 管理的一切都叫 unit,类型有十几种,日常打交道最多的就这几个:
| 类型 | 后缀 | 用途 |
|---|---|---|
| service | .service | 系统服务,最常用 |
| target | .target | 一组 unit 的集合,类似“运行级别” |
| timer | .timer | 定时任务,可替代 cron |
| socket | .socket | 套接字激活,按需拉起服务 |
| path | .path | 路径变化时触发服务 |
unit 文件放在两个地方:系统自带的在 /lib/systemd/system/,管理员自定义的在 /etc/systemd/system/,后者优先级更高。想覆盖系统默认行为,把文件拷到 /etc/systemd/system/ 下改就行,系统升级也不会丢。
三、systemctl:每天都在用的命令
systemctl start nginx # 启动服务
systemctl stop nginx # 停止服务
systemctl restart nginx # 重启服务
systemctl reload nginx # 重载配置(不断服务)
systemctl enable nginx # 开机自启
systemctl disable nginx # 取消开机自启
systemctl status nginx # 查看状态,最常用
systemctl is-active nginx # 只看是否在运行
systemctl list-units --type=service --state=running # 列出运行中的服务
排查问题三板斧:systemctl status 看状态和最近日志,journalctl -u nginx -f 实时跟日志,systemd-analyze blame 看开机时哪个服务最慢。
四、实战:手写一个 service 文件
假设你写了一个 Python 小服务 app.py,监听 8080 端口。以前的做法可能是 nohup python app.py &,机器一重启就没了,还得自己写守护脚本。现在用 systemd,几分钟搞定。
1. 创建 unit 文件 /etc/systemd/system/myapp.service:
[Unit]
Description=My Python App
After=network.target
Wants=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
几个关键字段解释一下:
After=network.target:网络就绪后再启动,避免服务起来时网络还没好;Type=simple:默认类型,ExecStart 启动的进程就是主进程;Restart=on-failure:异常退出自动重启,配合RestartSec=5等 5 秒再拉起,避免疯狂重启打爆日志;WantedBy=multi-user.target:决定enable时挂到哪个 target 下面。
2. 重载配置并启动:
sudo systemctl daemon-reload # 每次改完 unit 文件都要执行
sudo systemctl enable --now myapp # 开机自启 + 立刻启动
systemctl status myapp
3. 看日志,不用再到处找 log 文件:
journalctl -u myapp -f # 实时跟踪
journalctl -u myapp --since "1 hour ago" # 最近一小时的日志
systemd 把服务的标准输出直接收进 journal,日志从此有了统一入口。
五、几个容易踩的坑
- 改了 unit 文件没 daemon-reload:systemd 会缓存配置,不重载修改不生效,这是新手最高频的坑;
- Type 选错:程序自己会 fork 到后台的(比如默认配置的 nginx)要用
Type=forking,否则 systemd 以为进程退出了,会反复重启服务; - 环境变量:unit 里没有你的 shell 环境,
PATH、PYTHONPATH这类要靠Environment=显式声明; - 权限:用
User=指定运行用户,别图省事全用 root 跑业务进程。
六、小结
systemd 的学习曲线其实很平缓:先会用 systemctl 管理服务,再学会写 service 文件解决“开机自启 + 挂掉重启”,最后按需探索 timer 替代 cron、socket 激活这些高级玩法。把这套东西吃透,你手里的每一台 Linux 服务器都会听话很多。
- 点赞
- 收藏
- 关注作者
评论(0)