华为云 ECS 上把 Node.js 服务交给 systemd:从 nohup 迁移到可自愈部署
一、为什么不再用 nohup
在单机 ECS 上启动 Node.js 服务,最常见的做法是 nohup node server.js &。它能让进程在退出 SSH 后继续运行,但没有解决另外几个问题:服务器重启后不会自动拉起、进程崩溃后不会重试、日志散落在不同文件里、环境变量依赖当前 shell、停止服务时也缺少统一的优雅退出流程。
把服务交给 systemd,可以用一份 unit 文件统一描述启动命令、运行用户、环境变量、重启策略和日志去向,后续排障也只需要看 systemctl status 与 journalctl。
二、准备目录与运行用户
先创建一个不能登录的专用用户,避免服务以 root 身份运行:
useradd --system --home /opt/myapp --shell /usr/sbin/nologin myapp
mkdir -p /opt/myapp /etc/myapp
chown -R myapp:myapp /opt/myapp
chmod 750 /opt/myapp
环境变量单独放在 /etc/myapp/myapp.env,权限设为 600。不要把数据库密码、API Key 直接写进 unit 文件,因为 unit 文件通常会被复制、备份或提交到仓库。
NODE_ENV=production
PORT=3000
三、编写 unit 文件
新建 /etc/systemd/system/myapp.service:
[Unit]
Description=My Node Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=always
RestartSec=3
TimeoutStopSec=20
KillSignal=SIGTERM
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target
几个参数值得说明:ExecStart 使用 node 的绝对路径,因为 systemd 的 PATH 与登录 shell 不同;Restart=always 适合常驻 API 服务;RestartSec 留出退避时间,避免崩溃后瞬间重启风暴;TimeoutStopSec 给应用留出处理 SIGTERM 的时间,配合代码里的优雅关闭逻辑一起使用。
如果服务启动时会自行 fork 到后台,才考虑 Type=forking;普通 Node 进程保持 Type=simple 即可。
四、启用与验证
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -f
验证不要只看进程是否存在,还要做三件事:请求一次健康检查接口,确认返回正常;执行 systemctl restart myapp,确认重启后能自动恢复;执行 systemctl stop myapp,确认进程能在超时时间内退出,而不是被强制杀死。最后重启一次 ECS,确认开机后服务会自动拉起。
五、健康检查的边界
systemd 的重启策略只能判断进程是否退出,不能判断服务是否真的可用。进程还在但数据库连接池耗尽、事件循环被阻塞,systemd 不会知道。更稳妥的做法是提供 /healthz 接口,再用外部定时任务请求它,失败时告警或执行重启。若希望 systemd 参与健康判断,可以使用 WatchdogSec 配合 sd_notify,让应用定期上报心跳;没有上报就由 systemd 重启。
六、常见坑
- 直接写
node而不是绝对路径,导致 unit 启动时报找不到命令。 - 环境变量文件权限过宽,或路径写错,服务启动后读不到配置。
- 非 root 用户监听 1024 以下端口失败,应改用 3000 等高位端口并由 Nginx 反向代理。
- 没有设置
WorkingDirectory,相对路径读取静态文件或证书时失败。 - 应用崩溃后立即重启,形成无限循环,应结合
StartLimitIntervalSec与StartLimitBurst限制。 - 日志无限增长,需要配置 journald 的保留上限或定期清理。
七、上线检查清单
专用运行用户、环境变量文件权限 600、绝对路径启动、合理的重启与停止超时、健康检查与告警、日志保留策略、重启 ECS 后的自恢复验证。把这七项确认一遍,单机 Node.js 服务就具备了最基本的可运维性。
- 点赞
- 收藏
- 关注作者
评论(0)