Go健康端点必须匹配Service selector的就绪逻辑,即readinessProbe需做轻量级依赖检查、与livenessProbe路径分离、配置合理超时及初始延迟,并在优雅关闭时主动控制isReady状态以确保Endpoint及时更新。

Go健康端点必须匹配Service selector的就绪逻辑
Service本身不检查健康状态,但它依赖Endpoint Controller从readinessProbe结果中动态更新Endpoints列表。如果Go写的/healthz返回200但实际DB连不上,Service仍会把流量导过去——因为K8s只看探针HTTP状态码,不管业务是否真可用。
实操建议:
- readinessProbe的handler必须做轻量级依赖检查:
db.PingContext(ctx, 2*time.Second)、redis.Ping(),超时设为timeoutSeconds - 1 - 不要复用livenessProbe的路径;liveness可只查
atomic.LoadInt32(&healthy),避免DB抖动触发误重启 - 在Deployment里显式配置
readinessProbe.initialDelaySeconds: 10,给Go初始化留出时间(比如加载配置、建gRPC连接) - 验证方式:删掉Endpoints后
kubectl get endpoints应为空;恢复健康后立刻回填my-service
Service selector切蓝绿时,readinessProbe决定切换成败
蓝绿发布中,你改的是Service的selector(比如从version=blue切到version=green),但新Pod能否立刻承接流量,取决于它的readinessProbe是否通过。如果probe失败,Endpoints不会加入,Service看似切换了,实际没流量过去。
常见错误现象:
- 切完
kubectl get endpoints显示1/1但curl -v http://service-name超时——说明Pod已进Endpoints,但服务没监听对的端口 - 切完Endpoints始终是
0/1——大概率是Go没监听targetPort指定的端口,或/ready路径返回非200 - 切完部分请求503,部分正常——readinessProbe的
periodSeconds太短,DB临时抖动导致Pod被反复摘入
关键参数配比建议:periodSeconds: 10 + failureThreshold: 3,容忍30秒内偶发失败。
Ingress健康检查与Service探针不是一回事
ingress-nginx默认每10秒对Pod发GET请求到/healthz(走Service ClusterIP),这个探测和你的readinessProbe配置无关。它失败会导致Ingress把Pod从upstream摘掉,即使Service的Endpoints里还有它。
所以必须保证:
- Go代码里注册了
http.HandleFunc("/healthz", ...),且返回200(别重定向、别返回503) - 这个handler和readinessProbe的逻辑一致,但可以更轻——Ingress探测不关心DB,只确认进程活着就行
- Service的
targetPort和GoListenAndServe(":8080", ...)端口严格一致;写错会直接404或connection refused - 若用了Ingress path rewrite(如
rewrite-target: /),健康检查仍走根路径,不受rewrite影响
优雅关闭时主动控制readiness状态
K8s发SIGTERM后,Pod进入Terminating状态,但Service不会自动把它从Endpoints摘掉——得靠readinessProbe返回非200来触发摘除。否则长连接还在,新请求却打不进来,造成请求丢失或超时。
Go里最简实现:
- 定义全局原子变量:
var isReady int32 = 1 - readiness handler里加判断:
if atomic.LoadInt32(&isReady) == 0 { http.Error(w, "not ready", http.StatusServiceUnavailable); return } - SIGTERM处理函数里先置
atomic.StoreInt32(&isReady, 0),再等所有HTTP连接drain完(用server.Shutdown())
这一步漏掉,蓝绿切换时旧Pod可能还在收请求,新Pod又没完全ready,就会出现短暂503或请求堆积。
真正卡住蓝绿切换的,往往不是Service YAML写错,而是Go健康端点没按K8s的节奏响应——它不理解“就绪”和“存活”的语义差异,也不管你有没有优雅关机。盯住endpoints和pod status,比盯着YAML更容易定位问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











