华为云 ECS 上把 Node.js 服务交给 systemd:从 nohup 迁移到可自愈部署

举报
yd_219023509 发表于 2026/10/26 07:46:40 2026/10/26
【摘要】 从 nohup 迁移到 systemd:专用用户、环境变量、unit 配置、重启策略、优雅停止与健康检查,附一份可直接照做的上线检查清单。

一、为什么不再用 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 服务就具备了最基本的可运维性。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。