Go微服务Kubernetes滚动部署核心是适配K8s生命周期:必须监听SIGTERM并调用http.Server.Shutdown()配超时,分离readinessProbe(/readyz查依赖)与livenessProbe(/healthz仅查进程),且Deployment selector与Pod labels严格一致。

Go 微服务在 Kubernetes 上实现滚动部署,核心不是“让 Go 做滚动”,而是让 Go 服务能被 Kubernetes 安全、准确地逐个替换——这取决于信号处理、探针设计、配置对齐三件事是否到位。缺一不可。
必须监听 SIGTERM 并调用 http.Server.Shutdown()
Kubernetes 在滚动更新时发的是 SIGTERM,不是 SIGKILL。如果你只捕获 os.Interrupt(本地 Ctrl+C 场景),或者压根没监听信号,旧 Pod 会被强制终止,正在处理的 HTTP 请求、gRPC 流、DB 事务都会中断。
-
http.Server.Shutdown()是阻塞调用,必须配context.WithTimeout(),建议 15–30 秒;超时后应直接os.Exit(1),别等 - 所有 defer 清理逻辑(如
db.Close()、consumer.Stop())必须放在Shutdown()返回之后执行,顺序反了会丢数据 - 禁止在 Shutdown 流程中用
log.Fatal()或 panic —— 它们绕过 defer,导致连接池未释放、etcd lease 未撤销
readinessProbe 和 livenessProbe 必须指向不同端点
共用一个 /healthz 是线上高频误配。Kubernetes 会在容器启动后立刻发起 liveness 探测,而此时你的 DB 连接可能还没建好、gRPC 客户端还在重连 —— 导致新 Pod 被反复重启,滚动卡死。
-
livenessProbe指向/healthz:只检查进程是否卡死,返回 200 即可,不查下游 -
readinessProbe指向/readyz:必须真实检查依赖,比如db.Ping()、redis.Conn().Ping()、grpcClient.Check() - 务必设
initialDelaySeconds: 10和failureThreshold: 3,避免 GC STW 或慢初始化触发误判
Deployment 的 selector.matchLabels 和 Pod template labels 必须严格一致
这是最常被忽略的硬性约束。一旦 Deployment 创建成功,spec.selector 就不可变更;如果 template 里 labels 多了字段(比如加了 version: v2),但 selector 没同步,新 Pod 永远不会被纳入 Service 流量,也不会被旧 ReplicaSet 清理 —— 表现为“新镜像已拉起,但没流量”。
- 写法必须完全对齐,例如:
matchLabels: {app: "order-svc"}→ template 中labels: {app: "order-svc"} - 不要在 template 里额外加 label,除非 selector 明确包含它;CI/CD 中建议用
envsubst注入,避免手误 - 修改 label 后 K8s 会报错:
field is immutable,只能删掉重建 Deployment
maxSurge 和 maxUnavailable 要按 Go 服务特性调
Go 服务通常连接数高、冷启动快,但并发请求处理中突然缩容容易引发客户端重试风暴。默认值不一定合适。
-
maxSurge: 1(允许多起 1 个新 Pod)+maxUnavailable: 0(保证旧 Pod 全部在线直到新 Pod 就绪)是最稳妥组合 - 设
minReadySeconds: 15,确保新 Pod 启动后至少稳定运行 15 秒才被认为“就绪”,避开初始化毛刺 - 如果用了连接池或长连接(如 WebSocket),
maxUnavailable设为 0 更关键 —— 否则客户端会感知到连接断开
滚动部署真正卡住的地方,往往不在 YAML 写错,而在 Go 代码里没响应 SIGTERM、探针返回假健康、或者 label 对不上。这三处任何一个出问题,Kubernetes 就会停在“1/3 更新完成”不动,而日志里可能只显示 “Pod is not ready”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











