Go原生不提供K8s健康检查实现,但net/http handler可对接livenessProbe和readinessProbe:/healthz仅检查进程存活(如原子变量),返回200且无body;/readyz可查DB等依赖,但须设≤2s超时,避免误重启或流量错发。

Go 原生不提供 Kubernetes 特定的健康检查实现,但 net/http 的标准 handler 完全能对接 livenessProbe 和 readinessProbe——关键不是“支持”,而是怎么写得不踩坑。
HTTP handler 必须返回 200 且无 body
Kubernetes 的 probe 默认只看 HTTP 状态码,body 内容被忽略;返回非 200(比如 500、404)或超时会触发重启或剔除流量。
- 不要在 handler 里写
log.Fatal或 panic,这会让整个进程退出,probe 直接失败 - 避免调用可能阻塞的外部服务(如数据库 ping)——
readinessProbe可以查依赖,但必须设好超时和重试,否则影响滚动更新 - 最简实现就是:
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })
区分 liveness 和 readiness 的逻辑边界
很多人用同一个 endpoint 应对两种 probe,但语义不同:liveness 表示“进程是否还活着”,readiness 表示“能否接收流量”。混用会导致误杀或流量打到未就绪实例。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
/healthz适合做 liveness:只检查进程内基础状态(如 goroutine 是否卡死、内存是否爆满),不依赖外部系统 -
/readyz适合做 readiness:可检查 DB 连接、Redis、下游 gRPC 服务等,但所有检查必须有明确超时(建议 ≤2s) - 若用同一端点,K8s 无法区分意图;更糟的是,liveness 失败会 kill pod,而 readiness 失败只是摘流量——别让 DB 挂了就把整个 pod 干掉
Probe 配置要匹配 Go 服务的实际响应行为
Go 默认 HTTP server 没有优雅关闭超时控制,而 K8s probe 的 initialDelaySeconds、timeoutSeconds 必须和你的 handler 实际耗时对齐。
立即学习“go语言免费学习笔记(深入)”;
- 如果
/readyz里做了 DBPingContext,且 DB 延迟偶尔达 3s,那timeoutSeconds: 1就必然失败 -
periodSeconds别设太小(如 2s):高频 probe + 高负载下可能压垮服务,尤其 readiness 检查带 DB 查询时 - 务必在 handler 开头加
r.Context().Done()监听,防止 probe 请求卡住后 goroutine 泄漏:http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second) defer cancel() select { case <-ctx.Done(): http.Error(w, "timeout", http.StatusServiceUnavailable) return default: // 实际检查逻辑 } })
最常被忽略的是 context 传递和超时控制——不是 handler 写对了就行,K8s 的 probe 参数和 Go 的 HTTP 处理必须成对校准,否则线上会看到大量 “CrashLoopBackOff” 或 “NotReady” 却查不到原因。

















