健康检查 endpoint 必须返回 200 且无 body;livenessProbe 仅依赖状态码,readinessProbe 则需检查依赖;/livez 和 /readyz 应分离注册,禁用阻塞、panic 和外部调用。

健康检查 endpoint 必须返回 200 且不带 body
Kubernetes 的 livenessProbe 默认只看 HTTP 状态码,不是响应内容。哪怕你返回 {"status":"ok"},只要状态码是 200,它就认为存活;但如果响应体太大、耗时太久、或带了非标准 header(比如 Content-Encoding: gzip),某些旧版 kubelet 可能解析异常或超时失败。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
http.HandlerFunc直接写,避免中间件干扰(如日志、鉴权、CORS) - 不调用数据库、缓存、外部 API —— 健康检查必须是「本地瞬时判断」
- 不要用
json.NewEncoder(w).Encode(),它会自动设Content-Type: application/json并可能触发 gzip,改用w.WriteHeader(http.StatusOK)+ 空w.Write(nil) - 路径建议固定为
/healthz或/livez,和 Kubernetes 社区惯例对齐
如何区分 liveness 和 readiness?别混用同一个 handler
livenessProbe 判断进程是否卡死(比如 goroutine 泄漏、死锁),readinessProbe 判断能否接收流量(比如 DB 连上了没、配置加载完了没)。两者逻辑不同,强行共用一个 endpoint 是常见错误。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
liveness:只检查 runtime 是否正常 —— 比如runtime.NumGoroutine() < 10000,或time.Since(lastTick) < 30*time.Second(配合定时 tick goroutine) -
readiness:检查依赖服务连通性 —— 但必须加超时(context.WithTimeout),且失败时不 panic,只返回 503 - 两个 endpoint 要分开注册:
http.HandleFunc("/livez", liveHandler)和http.HandleFunc("/readyz", readyHandler) - 别在
livez里 ping MySQL —— 它挂了应该重启 pod,而不是让 kubelet 认为“活不了”然后反复 kill
HTTP handler 中禁止阻塞、panic 或忽略 error
健康检查 handler 被高频轮询(默认每 10 秒),一旦阻塞或 panic,整个 HTTP server 可能卡住或崩溃。Kubernetes 会持续重试,加剧问题。
常见错误现象:
- handler 里调
db.Ping()但没设 context timeout → 数据库慢时阻塞 30 秒,kubelet 直接判定失败 - 用
log.Fatal或os.Exit(1)→ 进程退出,pod 重建,形成雪崩 - 忘记处理
err != nil,直接把空指针传给json.Marshal→ panic
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有 I/O 操作必须带 context(
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)) - 用
defer cancel()防止 context 泄漏 - 错误统一转成 503(readiness)或 500(liveness 异常),不 panic、不 exit
- 用
http.Error(w, "db unreachable", http.StatusServiceUnavailable)明确语义
Go HTTP server 启动后才开始监听健康检查
如果 health endpoint 在 http.ListenAndServe 之前注册,但 server 没真正起来,kubelet 会收不到响应,立即触发重启循环(CrashLoopBackOff)。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 不要在
init()或包级变量中启动 server - 确保
http.ListenAndServe是 main goroutine 最后/唯一阻塞调用 - 若需预热(如加载配置、建连接池),放在
ListenAndServe之前,但健康 handler 注册必须在它之前完成 - 验证方式:启动后手动
curl -v http://localhost:8080/livez,确认返回 200 且无 body
最易被忽略的是:健康检查逻辑看似简单,但一旦掺杂了任意一点外部依赖、日志、中间件或 panic 处理不当,就会在高并发 probe 下暴露稳定性问题 —— 它不是“加个路由就行”,而是整个服务生命周期的守门人。










