go服务必须主动适配kubernetes生命周期:监听sigterm和os.interrupt信号,调用http.server.shutdown()优雅退出;分离/healthz(仅进程存活)与/readyz(检查db等依赖)探针;通过环境变量注入配置,禁用硬编码。

Go 服务在 Kubernetes 中不是“被管理”,而是必须主动响应生命周期信号和探针——不监听 SIGTERM、不分离 /healthz 和 /readyz、不设 preStop,就谈不上优雅。
Go 必须监听 SIGTERM 并调用 http.Server.Shutdown()
Kubernetes 在滚动更新或缩容时只发 SIGTERM,不会等你处理完请求就直接杀进程。如果你只监听 os.Interrupt(比如本地 Ctrl+C),线上会丢连接、中断 DB 事务、残留 goroutine。
- 必须同时注册
syscall.SIGTERM和os.Interrupt:前者是 K8s 正式信号,后者方便本地调试 -
http.Server.Shutdown()是阻塞调用,务必设超时(如ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)),超时后应强制os.Exit(1) - 所有清理逻辑(DB 连接池关闭、gRPC 客户端断连、消息消费者退出)必须放在
Shutdown()返回之后执行,顺序反了会导致资源被提前释放 - 禁用
log.Fatal()或panic退出:它们跳过defer和Shutdown()流程
readinessProbe 和 livenessProbe 必须指向不同端点
用同一个 /healthz 同时做就绪和存活检查,会导致 Pod 就绪前就被反复重启——因为 livenessProbe 在容器启动后立刻发起请求,而 HTTP server 可能还没 bind 成功。
-
livenessProbe指向/healthz:只返回200,不查 DB、不连下游,纯粹确认进程没卡死 -
readinessProbe指向/readyz:必须真实检查依赖,例如db.Ping()、redis.Conn().Ping()、grpcConn.ReadyState() == connectivity.Ready - YAML 中务必设置
initialDelaySeconds: 5(给 Go 程序冷启动留时间)和failureThreshold: 3(避免 GC STW 期间误判)
preStop 钩子与 Go 信号处理要协同,不能重复或遗漏
preStop 是容器终止前的最后机会,但它的执行时机和 Go 中的 SIGTERM 处理有重叠风险:如果两者都做同一件事(比如关 HTTP server),可能触发双 shutdown;如果 preStop 执行太慢,又会挤压 Go 自身的 Shutdown() 时间。
- 推荐只在 Go 代码中做完整 shutdown,
preStop仅用于兜底或同步动作(如写 final log、通知上游注销) - 若必须用
preStop,命令应设exec类型,并加timeoutSeconds: 10限制执行时长 -
preStop不替代 Go 的信号监听——它无法捕获 Go runtime 内部状态,也无法控制Shutdown()超时逻辑
Deployment 的 selector.matchLabels 和 Pod template labels 必须字面一致
这是最常被忽略的硬约束:一旦 Deployment 创建成功,spec.selector 就不可变更;如果 template 中 labels 缺字段、值不一致、或多写了 label(如 version: "v1"),新 Pod 永远不会被 Service 收入流量,也不会被旧 ReplicaSet 清理。
- 写法必须严格对齐,例如:
matchLabels: {app: "user-svc"}→ template 中labels: {app: "user-svc"} - 不要在 template 里加额外 label,除非 selector 显式包含它
- CI/CD 中建议用
envsubst或 Helm 注入 label 值,避免手误导致部署静默失败
真正难的不是写完 Shutdown(),而是确保它在 SIGTERM 到达后、preStop 执行前、探针切换就绪状态之间,始终处于可控节奏——Kubernetes 不会等你,它只认信号、探针响应时间和 label 对齐度。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











