Consul健康检查必须配置Check字段,推荐用Check.HTTP主动轮询/health端点;HTTP需填完整可达URL、返回200且无重定向,显式设Timeout和Interval,避免critical状态。

Consul 健康检查必须用 HTTP 轮询,不能只注册服务不配 Check
Consul 默认不会主动探测你的 Gin 服务是否真能干活——它只认你注册时声明的 Check 字段。如果漏掉或填错,服务虽然显示在目录里,但状态永远是 critical,下游调用方查到的实例全是“假活”。
最稳妥的方式是配置 Check.HTTP,让 Consul 主动 GET 你的 /health 或 /readyz 端点:
-
Check.HTTP必须填完整 URL(如"http://10.0.1.5:8080/health"),不能是相对路径或localhost - 响应必须是 HTTP 200,且不能有重定向(301/302);否则 Consul 认为检查失败
-
Check.Timeout要显式设(比如"2s"),默认 10s 太长,可能掩盖慢依赖问题 -
Check.Interval建议设为"5s"~"10s",太短会压垮服务,太长则故障发现延迟
Gin 的 /health 和 /readyz 必须物理隔离、逻辑分离
Kubernetes 的 livenessProbe 和 readinessProbe 语义完全不同,混用一个端点等于放弃控制权。
/health 只做三件事:确认 HTTP server 正在 Accept 连接、主 goroutine 没 panic、进程没被 SIGSTOP:
- 不要走任何中间件(JWT、CORS、日志),避免 401/403 导致探针失败
- 注册方式必须绕过全局中间件:
r.NoRoute()里判断路径,或在r.Use()之前单独注册 - 响应体可极简:
{"status":"ok"},不查 DB、不连 Redis
/readyz 则必须并发探测关键依赖:
- 用
errgroup.Group并发执行db.PingContext()、redis.Ping()、http.Head()等 - 每个检查必须带独立超时:
ctx, cancel := context.WithTimeout(c.Request.Context(), 2*time.Second) - 任一关键依赖失败,整体返回 HTTP 503;非关键项降级可返回 200 +
"degraded": true
Consul 注册代码里不能只调一次 ServiceRegister
如果你选的是 Check.TTL 类型(不推荐),就必须自己维护心跳——Consul 不会帮你续期。Gin 启动后只注册一次,TTL 一过服务就从目录消失,但进程还在跑,形成“僵尸注册”。
正确做法是改用 Check.HTTP,彻底免心跳。如果非要用 TTL:
- 注册时设
Check.TTL = "10s" - 另起 goroutine,每
5s调一次agent.UpdateTTL("service-id", "pass", "") - 务必监听
ctx.Done(),服务退出前发送"fail"终止注册
更常见错误是注册时没传 Check 字段,只传了 Name 和 Address——这会导致 Consul 标记为 critical 并静默剔除,查 consul catalog services 看不到,但 consul health service your-service 里全是 failing。
Docker/K8s 环境下 Consul 的 GRPC 或 HTTP 地址必须网络可达
Consul agent 运行在宿主机或独立容器里,它访问你的 Gin 服务时,不是走 localhost,而是走真实网络路径。
常见填错的地址:
-
"http://localhost:8080/health"→ Consul 在宿主机上,localhost 指向它自己,不是你的服务容器 -
"http://127.0.0.1:8080/health"→ 同上,且 Docker 容器内 127.0.0.1 是容器自身,不是宿主机 -
"http://gin-service:8080/health"→ 仅当 Consul 和 Gin 在同一 Docker 自定义 network 中才有效
安全做法是启动 Gin 前获取本机非 loopback IPv4 地址:
ip, _ := localIP() // 自行实现,排除 127.0.0.1
healthURL := fmt.Sprintf("http://%s:%s/health", ip.String(), port)
然后把这个 healthURL 填进 Consul 的 Check.HTTP 字段。Kubernetes 下同理,用 status.hostIP 或 headless service DNS 名(如 gin-service.default.svc.cluster.local)。


















