kubernetes deployment 实现滚动发布,go 应用需配合 sigterm 处理、readinessprobe 配置及 maxsurge/maxunavailable 参数设置,确保平滑更新不丢请求。

滚动发布不是 Go 本身的功能,而是 Kubernetes Deployment 控制器的行为;Go 应用要配合它不掉连接、不丢请求,关键在信号处理、探针配置和更新参数设置。
Go 程序必须捕获 SIGTERM 并调用 server.Shutdown()
Kubernetes 终止 Pod 时发的是 SIGTERM,不是 SIGKILL。如果 Go 不监听它,进程会立即退出,所有活跃 HTTP 连接被硬断开。
-
http.Server.Close()是暴力关闭,会中断所有连接;server.Shutdown()才是标准做法:拒绝新请求、等待已有 handler 返回 - 必须配
context.WithTimeout(),超时时间要小于 K8s 的terminationGracePeriodSeconds(比如设 30s,K8s 配 45s) - 别在 handler 里启动 goroutine 后立刻返回——
Shutdown()不等后台 goroutine,会导致请求实际未完成就退出 - 记得关闭 DB 连接池、取消长轮询 context、释放文件句柄等后台资源
Kubernetes Deployment 必须显式配置 maxSurge 和 maxUnavailable
这两个参数不是可有可无的装饰字段,而是滚动更新节奏的刹车和油门。设错会导致卡住、秒级不可用,或资源争抢失败。
-
maxSurge: 1允许临时多跑 1 个 Pod(如从 3→4),否则新 Pod 拉不起来就卡住 -
maxUnavailable: 1保证任何时候至少有 2 个 Pod 在服务(3−1),避免流量断崖 -
maxSurge: 0是无效配置,会导致 rollout 卡住——新 Pod 根本起不来 - 低副本数(如
replicas=2)下,maxSurge: 25%实际为 0,可能触发“先删后启”
ReadinessProbe 必须反映真实服务能力
就绪探针不是摆设。Kubernetes 依赖它判断是否把流量导给这个 Pod;返回 200 不等于能干活。
- 检查数据库连通性、gRPC 连接池是否 ready、Redis 是否可 ping,而不是只写
return http.StatusOK - 设置
initialDelaySeconds(比如 3–5 秒),给 Go 应用留出初始化时间(DB 连接、缓存预热等) - 避免在
/health里做耗时操作(如全量缓存加载),否则可能拖慢滚动节奏甚至触发误驱逐 - 日志中记录启动完成时间点,并带 traceID,方便排查某次滚动中哪些实例延迟就绪
更新镜像后必须轮询 Deployment.status 判断完成
kubectl set image 或 Update() 调用成功,只表示 API Server 接收了变更,不代表滚动已结束。
- 真正判断完成需轮询 Deployment 的 status 字段
- 检查
status.updatedReplicas == status.replicas(所有副本都已更新) - 同时检查
status.availableReplicas == status.replicas(所有副本都已就绪) - 不要依赖
kubectl rollout status --watch就认为万事大吉——它默认只等 600 秒,超时可能静默失败
最常被忽略的一点:滚动更新期间新旧版本共存,如果接口不兼容或数据库迁移没同步,问题会在流量切换过程中集中暴露,但日志和指标可能分散在不同 Pod 上,查起来费劲。务必提前验证 schema 变更与服务兼容性,别等滚动到一半才发现 500 错误飙升。











