Go服务蓝绿部署关键在健康检查真实性和优雅关闭完整性:/readyz须探测核心依赖并缓存结果,readinessProbe timeout≥3s;Service selector切换或Argo Rollouts可实现零代码改动蓝绿,但需确保标签精确匹配、自动升级禁用并人工确认,同时shutdown必须等待所有goroutine退出。

Go 服务本身不做蓝绿部署,它只负责“准备好被切换”——只要健康检查真实、关闭逻辑完整、标签配对正确,Kubernetes 或 Argo Rollouts 就能完成蓝绿。
/readyz 必须检查依赖,不能只返回 200
很多团队把 /readyz 写成硬编码 {"status": "up"},结果新 Pod 还没连上数据库、Redis 连接池为空、gRPC client 没 ready,流量就切过去了,第一个请求直接 panic。
- 必须同步或异步探测核心依赖:DB ping、Redis SET/GET、下游 gRPC 的
HealthCheck方法 - 避免在 handler 里实时探测——用 goroutine 启动后定期刷新状态,
/readyz只读本地缓存布尔值 - 如果初始化耗时波动大(比如 config 加载 + migration),启动后加
time.Sleep(2 * time.Second)再开放就绪,比靠initialDelaySeconds更可控 - Kubernetes 中
readinessProbe的timeoutSeconds别设成 1;建议 ≥3,否则慢启动 Pod 直接被踢出 Endpoints
Service selector 切换是原生蓝绿最简路径
不用装 Argo Rollouts,两个 Deployment + 一个 Service 就够。关键不是“怎么写 Go”,而是“怎么配 YAML 和怎么切”。
- 两个 Deployment 共享
app: user-api,但用version: v1/version: v2区分 - Service 的
selector初始指向version: v1;验证 v2 Pod 全部Ready后,执行:kubectl patch service user-api -p '{"spec":{"selector":{"version":"v2"}}}' - 别用
kubectl apply -f覆盖整个 Service YAML——容易冲掉 CI 注入的 label(如git-commit) - 给 v2 Deployment 加
priorityClassName,防集群资源紧张时被 OOMKilled 导致就绪失败
优雅关闭必须覆盖所有活跃连接与后台任务
切流后旧 Pod 被删,但若没等完正在处理的请求或没停掉消息消费者,就会丢数据、502、半截响应。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- HTTP server 启动后保存
*http.Server实例,收到syscall.SIGTERM后调用srv.Shutdown(ctx),ctx带 15–30 秒超时 - 所有后台 goroutine(如 Kafka 消费、指标上报)必须接收
context.Context,并在ctx.Done()时 clean exit - 不要用全局 flag、无缓冲 channel 或
os.Exit(0)强退——这会中断正在进行的事务 - log 启动和关闭事件时带上 traceID:
log.Printf("[shutdown] graceful exit started, traceID=%s", traceID),方便在 Loki 里对齐切换时间点
Argo Rollouts 蓝绿只需改 YAML,Go 代码零改动
Argo Rollouts 是控制器,不是 SDK。你不需要在 Go 里 import 它、调它的函数,也不需要改 main.go。
- 把原 Deployment 替换成
RolloutCRD,strategy 设为blueGreen - 确保
activeService和previewService的 selector 与对应 Pod label 完全一致(注意拼写:是app: my-api还是app: my-api-v2?) -
autoPromotionEnabled: false推荐用于生产,切流前人工确认kubectl get rollout状态为Paused且 preview pods 全部 ready - 常见卡住现象:
Progressing状态不动,实际是/readyz返回非 200 或 probe 超时——先查 Pod 日志和kubectl describe pod里的 Events
最容易被忽略的点是:就绪探针是否真的代表“能干活”,而不是“进程活着”;以及 shutdown 是否真等完了所有 goroutine。这两处一漏,蓝绿就变成“看起来切了,其实炸了”。

















