技术文章2025 年 12 月 14 日约 2.5 分钟
Linux systemd 服务管理:从编写 unit 到故障排查
使用 systemd 管理自定义服务,覆盖 unit 文件、启动策略、日志查看和失败恢复。
systemd 已经是现代 Linux 的事实标准,但很多人的认知停留在 systemctl start/restart。这篇文章用「把一个 Node 服务做成开机自启」的完整过程,把 unit 文件、启动策略和排障讲透。
#unit 文件:三段各管什么
以 /etc/systemd/system/myapp.service 为例:
ini
[Unit]
Description=My App Service
After=network-online.target redis.service
Wants=network-online.target
[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/.env
ExecStart=/usr/bin/node /opt/myapp/dist/server.js
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
TimeoutStartSec=30
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target[Unit]:描述、依赖。After=只保证顺序,不保证服务已就绪;真正要等「就绪」得用 Type=notify 或 socket 激活,后面再说。[Service]:怎么跑、跑挂了怎么办。Type=simple表示 ExecStart 一启动就算 running,适合长驻进程。[Install]:WantedBy=multi-user.target配合enable实现开机启动。
改完 unit 必须 systemctl daemon-reload,否则 systemd 还用旧配置——这是新手最常犯的错,报错还是「Unit myapp.service not found」,其实是没 reload。
#重启策略:别让服务死在半夜
Restart=on-failure 表示只有异常退出才重启;on-abnormal 只在被信号杀死时重启。再配合:
RestartSec=5:崩溃后等 5 秒再拉起,防止「秒崩-秒启」风暴。StartLimitBurst=5+StartLimitIntervalSec=60:60 秒内最多重启 5 次,超过就放弃并进入 failed 状态——这个保护是必须的,没有它,一个配置错误的服务会把 CPU 打满在无意义的循环重启上。- 进程里要正确处理 SIGTERM:优雅关连接、刷盘、再退出。systemd 发 SIGTERM 后等
TimeoutStopSec(默认 90s),超时才 SIGKILL。
#排障:journalctl 是主战场
服务起不来,第一步永远先看日志,别急着改配置:
bash
systemctl status myapp # 状态 + 最近日志
journalctl -u myapp --since "10 minutes ago"
journalctl -u myapp -f # 跟随
journalctl -u myapp -p err # 只看错误级常见的几类失败和它们的日志特征:
Failed at step EXEC spawning /usr/bin/node: No such file or directory:ExecStart 路径错了,或User=指定的用户无权访问。which node确认绝对路径。- 启动后立刻
Main process exited, code=exited, status=1/:业务代码崩了,看应用日志。Restart会自动拉起,但如果StartLimitBurst被打满,状态会停在 failed。 - 端口占用:
ss -tlnp看谁占了,多半是上次进程没退干净。KillSignal=SIGTERM下有些进程不退,可以在 ExecStop 里加ExecStop=/bin/kill -TERM $MAINPID或直接KillMode=mixed。
#开机自启的完整姿势
bash
sudo systemctl daemon-reload
sudo systemctl enable --now myapp # enable 开机自启 + 立即启动
sudo systemctl is-enabled myapp # enabled
sudo systemctl list-units --type=service --state=running | grep myappenable --now 是我最常用的组合:一条命令同时完成注册和启动。最后提醒一句:生产环境改服务配置,先 systemctl cat myapp 确认 systemd 眼里实际的配置,防止你改的文件根本不在生效路径上(比如有的人改了 /etc/init.d/ 下的旧脚本,systemd 根本不看)。
写于 2025 年 12 月 14 日
- 栏目
- 技术文章
- 约
- 2.5 分钟
- 字数
- 2.1K
- 阅读
- 216
本文为原创记录,转载请注明出处。如果这篇替你省了时间,欢迎留言说说你踩到的坑。
同题 · related
- 把博客从 docker-compose 搬到 k3s:单机迁移与上线全过程在 4C3.6G 的云主机上把博客从 docker-compose 迁到单机 k3s。附完整 YAML 清单(Deployment、Service、PVC、Ingress、Certificate 等)与全部配置命令,记录部署、数据迁移与切换上线的踩坑过程。
- DevOps 运维中 AI 那些事把 AI 放进运维的真实分工:从服务器硬件、网络、GPU、内存,到虚拟化、Kubernetes、应用构建、CI/CD、可观测性、资源分配,再到 AI 自身的部署与算力调度。讲清楚哪些活它能接、边界划在哪、以及我踩过的那些坑。
- Shell 运维脚本基础:严格模式与安全参数处理用 set -Eeuo pipefail、参数校验、trap 清理与预览确认,写出半夜出事也不会闯祸的运维脚本。
留言 · remarks
00 条还没有留言,来说点什么吧。