Consul HTTP健康检查必须返回200且响应体为空;K8s中livenessProbe仅查进程自身状态,readinessProbe可查依赖服务;Go服务需显式设置HTTP Server超时并暴露/livez、/readyz、/health三个独立端点。

Consul HTTP健康检查必须返回200且响应体为空
Consul默认用HTTP状态码判断服务存活,200才认为健康,4xx或5xx直接标记为critical。它不解析响应体内容,但会严格校验HTTP头和状态码。
常见错误是返回{"status":"ok"}——这本身没问题,但若同时设置了Content-Type: application/json且未设Content-Length,某些Consul版本(如1.12之前)会因响应不完整而反复重试甚至超时失败。
- Go服务中用
http.HandlerFunc实现时,务必调用w.WriteHeader(http.StatusOK),再w.Write(nil)或直接return - 避免在handler里调用
log.Fatal或panic——这会让整个HTTP服务挂掉,Consul探测就全崩了 - 不要加
Cache-Control: no-cache以外的缓存头,Consul部分版本会因Vary头误判响应不可复用
K8s readinessProbe与livenessProbe的语义差异不能混用
K8s里readinessProbe决定是否往Pod转发流量,livenessProbe决定是否重启容器。两者用同一接口看似省事,实则埋雷。
典型翻车场景:把数据库连接检查塞进livenessProbe。一旦DB短暂抖动,K8s反复杀进程,导致连接风暴,DB更扛不住。
立即学习“go语言免费学习笔记(深入)”;
-
readinessProbe可以查DB、Redis、下游HTTP服务,只要它们不就绪,就别导流 -
livenessProbe只查进程自身:内存是否OOM、goroutine是否卡死、主循环是否还在运行(比如读一个chan bool) - Go里推荐用
http.ServeMux注册两个独立路径:/healthz(liveness)和/readyz(readiness),别共用/health - K8s默认
initialDelaySeconds: 0,新Pod可能还没初始化完就被探活,建议设为5秒以上
Go标准库net/http的超时配置直接影响探测稳定性
Consul和K8s的HTTP探测都依赖底层TCP连接和HTTP响应完成。如果Go服务没设好超时,一次慢请求可能拖垮整批探测。
现象是Consul UI显示服务“flapping”(频繁红绿切换),或K8s事件里出现Liveness probe failed: Get \"http://...\": context deadline exceeded。
- 必须给
http.Server显式设置ReadTimeout、WriteTimeout、IdleTimeout,三者都建议≤10秒 - 别依赖
context.WithTimeout包在handler里——探测请求本身没上下文,超时控制要落在server层 - 如果用了
gorilla/mux或chi等路由库,确认它们没覆盖掉server级超时;有些中间件会重置ResponseWriter,导致WriteTimeout失效 - 本地测试时用
curl -v http://localhost:8080/healthz看真实响应时间,别只信Postman的“200 OK”
Consul与K8s对/health端点的路径要求不一致
Consul默认探测路径是/或自定义的http字段值,而K8s要求明确指定httpGet.path。两者路径不同,硬写死一个地址会导致一方永远探不到。
更麻烦的是,Consul支持在服务注册时带check.http,K8s则靠YAML里的livenessProbe.httpGet.path,二者完全解耦,改错一个地方,另一个就静默失败。
- Go服务内部统一暴露三个端点:
/livez(liveness)、/readyz(readiness)、/health(Consul兼容) - Consul注册时,
check.http填http://localhost:8080/health;K8s YAML里livenessProbe用/livez,readinessProbe用/readyz - 别在
/health里做任何耗时操作——Consul默认每10秒探一次,且不支持并发限流,压测时容易打满 - 如果用
consul-template动态生成K8s YAML,注意模板里{{ .Service.Address }}可能是空,得fallback到127.0.0.1
最易被忽略的点:Consul的timeout字段单位是字符串(如"5s"),而K8s的timeoutSeconds是整数。写错格式不会报错,但探测行为完全失效——得去Consul日志里搜check timeout才能发现。










