★ 生产部署:nginx 反代 + supervisor/systemd
一句话结论:Go 服务部署的成熟形态是“静态编译二进制 + 反向代理 + 进程守护 + 优雅下线”。编译用 CGO_ENABLED=0 交叉编译出单文件;nginx 在最前面做 TLS 终止、静态资源、gzip、限流,并把请求反代到本机 Gin(127.0.0.1:8080),同时透传真实客户端 IP/协议头;进程守护用 systemd(现代发行版首选)或 supervisor 保证崩溃自动拉起;发布时先灰度切流,再向旧进程发 SIGTERM,Gin 侧用 http.Server.Shutdown 等处理完在途请求后退出。
编译与部署结构
CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags "-s -w" -o app ./cmd/server
# 目录:/opt/app/{bin/app, configs/prod.yaml}
nginx 反向代理
upstream gin_backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 443 ssl; # TLS 在 nginx 终止
location /api/ {
proxy_pass http://gin_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / { # 静态资源直接由 nginx 服务
root /opt/app/web/dist; # 配 expires/gzip
}
}
systemd 单元
[Unit]
Description=gin app
After=network-online.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/app
EnvironmentFile=/etc/app.env
ExecStart=/opt/app/bin/app -config=/opt/app/configs/prod.yaml
Restart=on-failure
RestartSec=3
LimitNOFILE=65535
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.target
supervisor 等价写法
[program:app]
command=/opt/app/bin/app -config=/opt/app/configs/prod.yaml
directory=/opt/app
user=www-data
autorestart=true
stderr_logfile=/var/log/app-err.log
stopsignal=TERM
systemd 与 supervisor 二选一即可:现代 Linux 优先 systemd(内核集成、资源限制丰富),supervisor 多见于老环境或 Python 运维栈;容器内则不该再套进程守护。
上线与优雅下线
- 灰度/滚动:先停一半流量 → 起新版本验证 → 全量切换;nginx 配合健康检查(/healthz)摘除不健康实例。
- 优雅停机:systemd stop / kill -TERM → Gin 里 signal.Notify 捕获 → server.Shutdown(ctx):停止接收新连接、等处理中的请求完成 → 关闭后台任务 → 退出。
追问记忆点
- 追问:为什么 Go 服务前面还要 nginx?——TLS、静态缓存、gzip、限流、多实例负载均衡、防直接暴露,都是 nginx 的成熟能力。
- 追问:Shutdown 和直接退出区别?——Shutdown 等处理中的请求跑完再关,避免用户请求被拦腰截断;超时要兜底强杀。
- 追问:Restart=on-failure 为什么不是 always?——on-failure 在正常 stop 时不拉起,方便主动停机发布。
- 记忆点:静态编译 + nginx 反代透传头 + systemd/supervisor 守护 + SIGTERM 优雅下线。