就绪探针要求http状态码必须为200,返回204、201等其他成功状态码会被kubernetes判定为失败;路径需严格匹配且不带尾斜杠;handler须轻量、设超时、用atomic缓存状态,响应体仅限"ok"。

就绪探针要求的HTTP状态码必须是200
就绪探针(readiness probe)只认 200 OK,返回其他成功状态码(比如 204 No Content 或 201 Created)会被Kubernetes判定为失败。哪怕逻辑完全正确,只要HTTP状态码不是 200,Pod就会被从Service的Endpoint中摘除。
Go标准库的 http.ServeHTTP 默认写入的是 200,但一旦你显式调用 w.WriteHeader(),就必须确保它传入的是 http.StatusOK(即200)。常见错误是误用 http.StatusNoContent 做健康检查返回,结果探针持续失败。
- 始终用
http.StatusOK,不要依赖默认值或自定义状态码 - 避免在 handler 中提前调用
w.WriteHeader()后又写 body —— Go会忽略重复的 status 写入,但行为不可靠 - 如果需要返回 JSON,记得设
w.Header().Set("Content-Type", "application/json"),否则某些旧版kubelet可能解析异常
接口路径必须与deployment中配置的path严格一致
Kubernetes不会自动补尾部斜杠,path: "/readyz" 和 path: "/readyz/" 是两个不同路径。Go的 http.ServeMux 默认不处理路径末尾斜杠重定向,/readyz/ 会 404,除非你手动注册该路径或使用通配匹配。
推荐做法是统一约定路径不带尾部斜杠,并在代码里明确注册:
http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
- 检查 deployment YAML 中
readinessProbe.httpGet.path的值,复制到 Go handler 注册路径 - 不要依赖路由库的“模糊匹配”或中间件自动 trim slash —— kubelet 发起的请求非常原始,不带任何客户端修饰
- 若用 Gin/Echo 等框架,确保注册的是精确路径,例如 Gin 的
r.GET("/readyz", handler),而非r.Any("/readyz", ...)
超时和响应时间必须控制在probe timeoutSeconds内
就绪探针默认超时是1秒(timeoutSeconds: 1),而Go HTTP server默认读写超时是0(不限),但 handler 本身若执行过久(比如查DB、调外部API),会导致 probe 超时失败,反复重启 Pod。
针对 Kubernetes 仪表板和 Web UI 的浏览器自动化。适用于与 Kubernetes Dashboard、Grafana、ArgoCD UI 或其他 Web 界面交互。需要设置 MCP_BROWSER_ENABLED=true。
关键不是调大 timeoutSeconds,而是让 handler 快速失败或降级:
- 所有依赖(DB连接池、Redis、HTTP client)必须设短超时,例如
context.WithTimeout(ctx, 800 * time.Millisecond) - 避免在 readiness handler 中做真实业务逻辑校验;它只应检查本地可快速验证的依赖(如本地 socket 是否监听、内存是否充足)
- 若必须检查远端服务,用
net.DialTimeout替代完整 HTTP 请求,减少开销 - 加一层轻量缓存(如
atomic.Bool记录最近10秒内是否成功),避免每次 probe 都触发真实检查
不要在就绪探针里返回详细错误信息
Kubernetes 日志和事件里会记录 probe 失败时的响应体,但仅限前512字节。如果你返回长 JSON 错误栈或堆栈跟踪,既无意义又可能泄露敏感信息。就绪探针唯一职责是回答“此刻能否接收流量”,不是诊断服务问题。
正确的响应体应该极简:
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
- 禁止返回
{"status":"down","reason":"db connection refused"}这类结构化错误 - 日志另走标准输出,由采集器收集;probe 接口只做布尔判断
- 如果真要调试,用单独的
/debug/readyz路径,且不暴露给 kubelet —— 它不该出现在 readinessProbe 配置里
真正难的不是写一个返回200的接口,而是让这个接口在高负载、部分依赖故障、网络抖动时依然稳定地返回200或快速失败。多数就绪探针失效,都源于把“能启动”和“能服务”混为一谈。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










