Kubernetes探针不调用Go函数,仅发起标准HTTP GET请求至指定路径(如/livez),依据响应状态码(200表示成功,503表示未就绪)和超时判定结果;路径、端口、协议必须与Go服务监听配置严格一致,且handler须绕过中间件、避免外部依赖、明确设置状态码。

探针调用的是 HTTP 端点,不是 Go 函数
Kubernetes 的 livenessProbe 和 readinessProbe 不会“调用 Go 接口”或反射执行函数,它只发起标准 HTTP GET 请求到你指定的路径(如 /livez),然后看响应状态码和超时行为。你的 Go 代码要做的,就是注册一个匹配路径的 HTTP handler,并确保它返回符合预期的状态码(200 表示存活/就绪,503 表示未就绪,5xx 或超时则可能触发重启)。
常见错误包括:
- YAML 中配置
httpGet.path: /health,但 Go 里注册的是http.HandleFunc("/healthz", ...)—— 路径不一致直接失败 - handler 里只写
w.Write([]byte("ok")),没调w.WriteHeader(http.StatusOK),Go 默认返回200?不,net/http在没显式设状态码时会返回200,但某些中间件或框架(如 Gin)会覆盖它;K8s 只认状态码,不解析 body,漏设就等于返回0状态,探测失败 - 用
http.Redirect或返回302—— K8s 不跟随重定向,直接判为失败
路径、端口、协议必须三者严格对齐
探针能调通的前提是:Kubernetes 能从容器内部(或通过 kube-proxy)准确访问到你的 handler。这要求三个硬性一致:
-
httpGet.port必须等于容器内http.ListenAndServe监听的端口(如":8080"),且 Deployment 中containerPort也得是8080;写成8080和"8080"都可以,但不能是9000 -
httpGet.path必须与http.HandleFunc或框架路由注册的路径**完全一致**,包括大小写和尾部斜杠(/livez≠/livez/) -
httpGet.scheme默认是HTTP;若用了 HTTPS,必须显式设为HTTPS,且 Go 服务得监听 TLS(http.ListenAndServeTLS),否则连接被拒绝
调试技巧:进 Pod 执行 curl -v http://localhost:8080/livez,结果必须是 HTTP/1.1 200 OK 且无重定向、无超时。别依赖浏览器或外部 curl —— K8s 是从 Pod 网络命名空间发起请求的。
为什么 handler 里不能有日志、中间件或外部调用
探针每秒或每几秒高频触发,handler 的任何额外开销都会放大成稳定性风险:
- 日志中间件每秒打一条
/livez日志?几小时内日志卷就满,kubectl logs失效 - JWT 鉴权中间件拦截
/livez?返回401,K8s 当即杀 Pod - 在
/livez里调db.PingContext?DB 暂时抖动 1 秒,livenessProbe就失败,K8s 重启容器 —— 进程明明活着,却被当成死的干掉 - 用了
time.Sleep(2 * time.Second)?K8s 默认超时 1 秒,直接判定失败
正确做法:用 http.HandleFunc 单独注册,绕过所有中间件;检查仅限本地内存状态(如 atomic.LoadInt32(&isAlive))、goroutine 数量或 HTTP server 是否仍在 accept;响应体可空,但状态码必须明确。
readinessProbe 失败不重启,但流量会立刻被切走
readinessProbe 的 handler 可以查 DB、Redis、下游 gRPC,但逻辑必须满足两个硬约束:
- 任一依赖失败,必须返回
http.StatusServiceUnavailable (503),不能返回200+ body 里写"db: down"—— K8s 只看状态码 - 所有依赖检查必须并发、带超时(如
context.WithTimeout(ctx, 800*time.Millisecond)),总耗时压在 1 秒内;否则 K8s 判定超时,同样返回503
注意:readinessProbe 失败不会重启容器,但 Service 的 Endpoints 会立刻移除此 Pod IP,新请求不再打入。如果你在 handler 里做同步 DB ping,而 DB 正在恢复中,那这段时间所有请求都 503 —— 所以更稳妥的做法是后台 goroutine 定期探测并缓存结果,/readyz 只读快照。
最易被忽略的一点:initialDelaySeconds 必须 ≥ 你服务实测冷启动时间。比如配置加载+gRPC 初始化花了 12 秒,但 initialDelaySeconds: 5,前 7 次探测全失败,Pod 直接被 K8s 标记为 CrashLoopBackOff —— 不是代码问题,是配置比启动还急。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











