用 systemd 管理你的自建服务
之前跑自建服务都是 nohup ./app &,机器一重启就得手动再敲一遍,进程挂了也不知道。直到被坑了两次,才老老实实学了 systemd。其实就一个 unit 文件的事。
写一个 unit 文件
假设你的程序在 /opt/myapp/app,新建 /etc/systemd/system/myapp.service:
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/app --config /opt/myapp/config.yaml
Restart=on-failure
RestartSec=5
# 资源限制,防止失控
MemoryMax=512M
[Install]
WantedBy=multi-user.target
几个关键项:
Restart=on-failure:崩了自动拉起来,5 秒后重试。配合RestartSec别太短,避免死循环刷屏User=appuser:别用 root 跑应用,建个专用用户,权限最小化MemoryMax:内存泄漏时至少不会把整台机器拖死
常用命令
systemctl daemon-reload # 改完 unit 文件后重载
systemctl enable --now myapp # 开机自启 + 立刻启动
systemctl status myapp # 看状态
systemctl restart myapp # 重启
journalctl -u myapp -f # 看日志(实时)
journalctl -u myapp --since "1 hour ago" # 看最近一小时
journalctl 是真香,应用往 stdout 打的日志 systemd 自动收走,不用自己配 logrotate。
需要前置依赖怎么办
比如你的应用依赖 Redis,先等 Redis 起来了再起:
[Unit]
Description=My Application
After=network.target redis-server.service
Requires=redis-server.service
After 是顺序,Requires 是强依赖(Redis 起不来,我也不起)。大多数场景 After 就够了。
从 nohup 迁移的 checklist
- 确认程序支持前台运行(别
daemonize成后台,systemd 要接管进程) - 日志改打到 stdout/stderr,别写文件了,让 journal 接管
- 配置文件用绝对路径,别依赖当前工作目录(或者配好
WorkingDirectory) - 信号处理:
systemctl stop发的是 SIGTERM,程序要能优雅退出,别直接 kill -9 的写法
nohup 适合临时跑个任务,长期服务一律 systemd。这是区分"玩玩"和"生产"的分水岭。