Linux上服务(Systemd)自动重启
前言
有时因为各种原因,比如程序崩溃、内存不足等导致服务 down 掉,我们可以使用 systemd 让服务自动重启。
自动重启
在 Linux 上,让 Go 服务“崩溃后自动重启”最省心的做法就是:
不要把守护逻辑写进 Go 程序里,而是交给 systemd(Ubuntu/CentOS/Debian 均自带)。
systemd 会在进程退出码非 0 时立即帮你拉起,还能限制重启频率、记录日志、设置环境变量、开机自启,一条命令搞定。
服务
准备一个最小单元文件。
假设你的可执行文件放在 /data/wwwjarapi/8931mcws/xh-control-ws,示例中用 root 用户(生产环境建议创建专用系统用户运行)。
创建文件
1 | vi /etc/systemd/system/xh-control-ws.service |
内容
1 | [Unit] |
[Unit]:Description 为服务描述,After=network.target 表示等网络就绪后再启动。
[Service] 配置说明:
Type=simple→ 拉起进程就算启动完成User=root→ 用 root 身份跑(示例用,生产建议专用用户)Group=root→ 用户组 rootWorkingDirectory=…→ 先 cd 到该目录再启动ExecStart=…→ 要执行的命令(必须绝对路径)Restart=always→ 一挂就重启RestartSec=5s→ 等待5秒再重启StartLimitInterval=60s + StartLimitBurst=10→ 60 秒内超 10 次重启就放弃StandardOutput=journal→ 把 stdout 打进 systemd 日志StandardError=journal→ 把 stderr 也打进 systemd 日志
启用并立即启动
1 | sudo systemctl daemon-reload |
之后若修改过 .service 文件,需要先执行 daemon-reload 再 start 或 restart。
验证
手动 kill 进程:
1 | ps -ef | grep xh-control-ws |
几秒后执行 systemctl status xh-control-ws,应看到 Active: active (running),说明已被自动拉起。
查看状态
1 | systemctl status xh-control-ws |
查看实时日志:
1 | journalctl -u xh-control-ws -f |
服务启动/停止
正常停止/启动服务
1 | # 只停掉当前运行实例(下次开机若 enable 了仍会自启) |
彻底禁用自启(stop + disable)
1 | sudo systemctl disable --now xh-control-ws # --now 顺便帮你 stop |
环境变量
在 Linux 系统中使用 systemd 管理服务时,若需为服务进程注入环境变量(如 JAVA_HOME、PATH、自定义配置等),不能依赖用户 shell 配置文件(如 ~/.bashrc、/etc/profile),因为 systemd 服务默认运行在一个“干净”的隔离环境中,不会加载这些交互式 shell 的环境变量 。
以下是 systemd 中设置环境变量的主流方式,按推荐程度和适用场景分类说明:
Environment
直接在 service 文件中使用 Environment=(适用于少量变量)
这是最简单直接的方式,适合变量数量较少、值固定的场景。
示例:
1 | [Service] |
特点:
- 变量写死在服务文件中,便于审计。
- 支持带空格或特殊字符的值(用双引号包裹)。
- 修改后需执行
systemctl daemon-reload生效 。
✅ 推荐用于:关键路径(如
PATH、JAVA_HOME)或简单配置。
EnvironmentFile
通过 EnvironmentFile= 加载外部配置文件(适用于多变量或敏感信息)
当环境变量较多、需要区分开发/测试/生产环境,或包含敏感信息(如 API 密钥、数据库密码)时,推荐使用此方式。
步骤:
创建环境变量文件(如 /etc/myapp/env.conf):
1 | # /etc/myapp/env.conf |
在 service 文件中引用:
1 | [Service] |
安全建议:
对含敏感信息的文件设置严格权限:
1 | chmod 600 /etc/myapp/env.conf |
可组合多个 EnvironmentFile 实现分层配置(如 base + secrets + network)。
推荐用于:
生产环境、多变量管理、配置与代码分离。
使用 drop-in 覆盖配置
使用 drop-in 覆盖配置(override.conf)
无需修改原始 service 文件,适合运维人员动态调整环境变量。
操作:
1 | sudo systemctl edit myapp.service |
系统会自动创建 /etc/systemd/system/myapp.service.d/override.conf,内容如下:
1 | [Service] |
优点:
避免直接编辑主 service 文件,便于版本控制和回滚 。
通过包装脚本设置环境
通过包装脚本设置环境(兼容旧脚本,但不推荐长期使用)
若启动脚本严重依赖 .bashrc 或 /etc/profile,可临时使用此方法:
示例脚本
/opt/myapp/start.sh:
1 |
|
service 文件
1 | [Service] |
注意事项
- 性能略低(额外启动 shell 进程)。
- 可能引入不可控变量,破坏服务的确定性。
- 仅建议用于迁移过渡期 。
全局设置(谨慎使用)
可通过以下方式为所有 systemd 服务设置默认环境变量:
/etc/environment:纯键值对,无 shell 语法,适用于LANG、PATH等静态变量 。/etc/systemd/system.conf中的DefaultEnvironment=:影响所有 system 级服务(需重启生效)。
注意
❌ 不推荐:除非确实需要全局统一配置,否则会降低服务隔离性和可移植性。
调试与验证技巧
查看服务最终加载的环境变量:
1 | systemctl show myapp.service --property=Environment |
检查环境文件是否被正确读取:
1 | journalctl -u myapp.service |
在 ExecStart 中引用变量时,必须使用 ${VAR} 语法,而非 $VAR 。
总结
最佳实践建议
| 场景 | 推荐方式 |
|---|---|
| 少量固定变量 | Environment= 直接声明 |
| 多变量、敏感信息、多环境 | EnvironmentFile= + 权限控制 |
| 运维动态调整 | systemctl edit 创建 override.conf |
| 兼容旧脚本(临时) | 包装脚本 |
| 全局 PATH/LANG | /etc/environment |
核心原则:
不要依赖 shell 配置文件,显式声明或通过受控文件注入环境变量,以确保服务的可重复性、安全性和可维护性 。