Go服务systemd unit文件应设Type=simple;必须用绝对路径写ExecStart、配WorkingDirectory、User设专用用户;加StandardOutput=journal和StandardError=journal;Go代码需监听SIGTERM并优雅退出。

systemd service 文件必须设 Type=simple 还是 Type=notify?
Go 程序默认不实现 systemd 的 notify 协议,所以别乱用 Type=notify —— 否则 systemd 会一直等 READY=1,最终超时标记服务为 failed。
绝大多数 Go 服务用 Type=simple 最稳妥:systemd 在 ExecStart 进程 fork 后即认为启动成功,后续日志、存活都靠进程本身维持。
- 只有你显式调用
github.com/coreos/go-systemd/v22/daemon.SdNotify(false, "READY=1")时,才考虑Type=notify -
Type=forking更危险:Go 程序一般不 double-fork,systemd 会找不到主进程 PID - 如果用了
log.Fatal或 panic 后直接退出,Type=simple下 systemd 能正确捕获 crash 并按Restart=on-failure拉起
Go 二进制路径和工作目录怎么写进 .service 才不踩坑?
常见错误是把相对路径塞进 ExecStart,或者漏掉 WorkingDirectory,导致程序读配置失败、写日志报 permission denied。
Go 编译出的二进制是自包含的,但它的行为高度依赖运行时路径 —— 尤其当你用 os.Open("config.yaml") 或 log.SetOutput(&os.File) 时。
立即学习“go语言免费学习笔记(深入)”;
-
ExecStart必须写绝对路径,比如/opt/myapp/bin/myapp,不能是./myapp或myapp - 务必配
WorkingDirectory=/opt/myapp,和你的配置文件、日志目录位置对齐 - 避免用
User=root;推荐新建专用用户,比如User=myapp,并确保该用户对二进制、配置、日志目录有 r-x / r-- / w- 权限
为什么 journalctl -u myapp.service 看不到 stdout 输出?
不是 journalctl 有问题,而是 Go 默认的 log 包输出到了 stderr,而部分旧版 systemd(如 CentOS 7)默认只把 stdout 接入 journal,stderr 被丢弃或截断。
更麻烦的是:如果你在代码里混用 fmt.Println(stdout)和 log.Println(stderr),日志会分散、时间错乱、甚至丢失。
- 统一重定向:启动时加
StandardOutput=journal和StandardError=journal到 service 文件 - Go 侧建议关闭默认 logger,改用
log.New(os.Stderr, "", log.LstdFlags)—— 因为 systemd 对 stderr 的采集更稳定 - 不要依赖
os.Stdout打调试日志;上线环境一律走log+os.Stderr,否则journalctl查不到关键信息
如何让 Go 服务收到 SIGTERM 并优雅退出?
systemd 发送 SIGTERM 后,默认等待 10 秒(TimeoutStopSec),然后发 SIGKILL 强杀。Go 程序若没监听信号,会立刻终止,数据库连接、HTTP 连接、队列消息全丢。
Go 原生支持信号处理,但必须主动注册,且不能只靠 os.Interrupt(那是 Ctrl+C)。
- 用
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)监听SIGTERM - 收到后启动 shutdown 流程:关闭 HTTP server(
srv.Shutdown(ctx))、释放 DB 连接池、提交未完成任务 - 务必在 service 文件中设
TimeoutStopSec=30,给足清理时间;别用默认 10 秒 - 别在 signal handler 里做阻塞操作(比如同步写磁盘日志),否则 systemd 等不及就强杀了
真正麻烦的从来不是写 service 文件,而是 Go 进程是否真能响应 SIGTERM、是否真把日志吐到 journal、是否在 chroot 或 CapabilityRestricted 环境下缺权限 —— 这些得一条条验证,不能只看 systemctl status 显示 active (running)。










