Golang健康检查在Kubernetes频繁失败,90%主因是Go服务未对齐K8s探测模型:/health返回200但Pod仍被杀,常因livenessProbe timeoutSeconds=1与DB/Redis无超时调用冲突、框架中间件阻塞、未隔离探针端点、依赖检查误入/livez、client未复用及探针路径配置不一致所致。

直接说结论:Golang健康检查在Kubernetes频繁失败,90%不是探针配错了,而是Go服务没对齐K8s的外部探测模型——它不关心你“有没有在跑”,只认“能不能在timeoutSeconds内返回200/503”。
为什么/health返回200但K8s还在杀Pod
常见现象是日志里反复出现CrashLoopBackOff,kubectl describe pod显示Liveness probe failed,但手动curl -v http://pod-ip:port/health明明返回200。问题出在超时和阻塞上。
-
livenessProbe.timeoutSeconds默认是1秒,但你的/healthhandler里调了db.Ping()或redis.Client.Ping(),没设context超时,一次网络抖动就卡住3秒以上 - 用了Gin/Echo等框架的全局中间件(比如JWT校验、日志记录),探针请求被拦在中间件里,还没进路由就超时了
- handler里每次新建
sql.DB或redis.Client,fd耗尽后所有HTTP连接hang住,包括探针 - 没区分
/health/live和/health/ready,把依赖检查塞进liveness,导致DB一抖就重启
Go代码里必须绕开框架单独暴露探针端点
别用router.GET("/health", handler),哪怕你加了Use(middleware.SkipForPath("/health"))也不保险——中间件链本身就有开销,panic恢复机制也可能吞掉错误。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 用原生
http.ServeMux单独起一个轻量server:http.ListenAndServe(":8081", probeMux),和主业务端口隔离 -
/health/live只查进程快照:runtime.NumGoroutine()是否突增、关键channel是否closed、atomic.LoadInt32(&healthy) -
/health/ready才同步检查依赖,但必须带context:ctx, cancel := context.WithTimeout(r.Context(), 1500*time.Millisecond),超时立刻返回503 - 所有client复用启动时初始化的全局实例,绝不在handler里
redis.NewClient()
livenessProbe和readinessProbe参数怎么设才不打架
两个探针指向同一个路径、用同一套逻辑,是生产事故高发区。它们语义完全不同,配置必须错开。
立即学习“go语言免费学习笔记(深入)”;
-
livenessProbe用/health/live,initialDelaySeconds: 10(给Go runtime warmup),timeoutSeconds: 1,periodSeconds: 5,failureThreshold: 3 -
readinessProbe用/health/ready,initialDelaySeconds: 15(等DB连接池填满),timeoutSeconds: 3(依赖检查留余量),periodSeconds: 10 - 千万别设
failureThreshold: 1——网络抖动一次就摘流量或重启,等于主动制造雪崩 - 如果Go服务启动慢(比如加载大配置文件),加
startupProbe,否则liveness可能在main函数执行完前就开枪
最容易被忽略的坑:镜像构建和信号处理
很多团队改完Go代码、调好探针,上线还是失败,最后发现根子在Dockerfile和SIGTERM响应上。
- 构建镜像时漏了
GOOS=linux CGO_ENABLED=0,生成的二进制在Alpine里跑不起来,exec user process caused: no such file or directory,探针根本发不出去 - 收到
SIGTERM后没关掉readinessProbe,K8s以为你还Ready,继续往将死的实例转发请求 - 没用
sync.WaitGroup或context.WithCancel控制server shutdown,srv.Shutdown()卡住,preStophook超时,K8s强制kill -
readinessProbe路径写成/readyz,但YAML里配的是path: /health,大小写或拼写差一个字母,probe永远404

















