平滑过渡依赖deployment控制器、go程序响应sigterm、探针真实就绪三者协同;仅改镜像字段触发滚动更新,需配shutdown()、合理探针及maxsurge/maxunavailable参数。

平滑过渡不是靠 Go 代码“热更新”实现的,而是 Kubernetes 的 Deployment 控制器 + Go 程序正确响应 SIGTERM + 探针真实反映就绪状态三者协同的结果。漏掉任意一环,都会出现请求中断、502、连接重置或新 Pod 被打爆。
改 Deployment 镜像字段,别删 Pod
滚动发布本质是让控制器创建新 Pod、淘汰旧 Pod,不是手动替换。用 client-go 直接改 deployment.Spec.Template.Spec.Containers[0].Image 后调用 Update(),是最小可靠路径。
- 必须只改
PodTemplateSpec内容(如image或带时间戳的annotation),否则 K8s 认为模板未变,不触发 rollout - 不要碰
ResourceVersion:client-go会自动处理;手动改会导致409 Conflict - 绝对避免
Delete+CreatePod:绕过控制器,副本数、健康等待、批次控制全失效
Go 程序必须用 http.Server.Shutdown() 响应 SIGTERM
SIGKILL 是强杀,SIGTERM 是通知你“准备退出”。Go 不监听它,默认收到就立刻退出,所有连接硬断开。
- 在
main()开头注册:signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT) - 收到信号后启动
server.Shutdown(),但必须配context.WithTimeout(),超时时间要 小于 K8s 的terminationGracePeriodSeconds(比如设 30s,K8s 配 45s) - 别在 handler 里启 goroutine 后直接返回——
Shutdown()不等后台 goroutine,请求实际未完成就退出 -
server.Close()是暴力关闭,会中断所有连接;Shutdown()才是标准做法
readinessProbe 必须检查真实依赖,不能只 ping 端口
90% 的流量抖动,源于探针返回 200 却没连 DB、没建缓存、下游 gRPC 还没 ready。K8s 把这种“假就绪” Pod 加入 Endpoints,流量进来就 panic。
- 独立路径用
/readyz,和/healthz分开 - probe 逻辑要检查:
db.Ping()、redis.Conn().Ping()、关键配置文件是否存在、必要初始化是否完成 - 设
initialDelaySeconds: 10,避免容器刚启就狂 probe;periodSeconds: 5足够,太频繁加重负载 - 别用
exec调curl:镜像里可能没装,且引入 shell 启动开销
maxSurge 和 maxUnavailable 必须按副本数对齐业务
默认 25% 在低副本场景下极危险。比如 2 副本,maxSurge: 25% ≈ 0,maxUnavailable: 25% ≈ 0,结果 rollout 卡住——新 Pod 根本起不来。
- 写死更稳:
maxSurge: 1+maxUnavailable: 0:先启一个新 Pod,等它通过 readiness 检查后再删旧 Pod(接近蓝绿) -
maxSurge: 0是无效配置,会导致 rollout 挂起 - 写敏感服务务必设
maxUnavailable: 0,避免新旧 Pod 并发写导致数据错乱或 buffer 丢失 - 加
minReadySeconds: 10:新 Pod 启动后至少等 10 秒才进 Endpoints,给缓存预热、gRPC 连接池建立留出时间
最容易被忽略的是资源清理:Shutdown() 不会自动关 DB 连接池、Redis 连接、日志句柄或长轮询 goroutine。这些都得在 Shutdown() 调用前手动加 db.Close()、log.Sync()、显式停止并等待后台任务结束。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











