Kratos默认不提供健康检查接口,因其遵循“无侵入”设计原则,不强制约定路径或行为,需用户手动注册如/healthz并返回200,否则K8s探针因404反复重启容器。

Kratos 服务必须显式暴露 /healthz(或自定义路径)HTTP 接口,且返回 200 状态码,否则 Kubernetes/Liveness Probe 会反复重启容器。
为什么 Kratos 默认不带健康检查接口
Kratos 是一个“无侵入式”框架,它不强制约定健康检查路径或行为——这和 Spring Boot Actuator 不同。它把探活逻辑完全交给使用者:你用什么方式暴露、用什么状态判断、是否集成 metrics 或 registry 状态,全由你控制。
常见错误现象:Liveness probe failed: HTTP probe failed with statuscode: 404,本质是没注册 handler,或者路由写错(比如注册在 /health,但 probe 配置的是 /healthz)。
- 必须手动注册一个 HTTP handler,路径要和 Helm/K8s 的
livenessProbe.httpGet.path完全一致 - 不要依赖中间件自动注入——Kratos 的
transport.HTTPServer不会自动挂载任何健康端点 - 如果用了 gRPC Server,健康检查仍需走独立 HTTP 端口(gRPC-Health-Probe 是另一套机制,K8s 原生不支持)
如何在 Kratos 中注册 /healthz 接口
最简实践是在 main.go 的 HTTP Server 初始化后,直接调用 mux.Handle() 注册:
// 在 http.NewServer() 之后
srv := http.NewServer(
http.Address(":8000"),
http.Middleware(
// ... 其他中间件
),
)
srv.Handle("/healthz", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok","timestamp":` + strconv.FormatInt(time.Now().Unix(), 10) + `}`))
}))
注意要点:
- 路径必须是绝对路径(
"/healthz"),不能带前缀或 router group - 别用
http.ServeMux全局注册——Kratos 的http.Server内部用的是私有 mux,要通过srv.Handle() - 如果服务同时启了多个 HTTP Server(比如 admin 端口),每个都要单独注册健康接口
进阶:把 registry/DB 连通性纳入健康检查
单纯返回 200 不代表服务真正可用。生产环境建议检查下游依赖,例如 Consul 连通性、MySQL 连接池是否 ready:
srv.Handle("/healthz", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
<pre class="brush:php;toolbar:false;">// 检查 registry
if reg := app.GetRegistry(); reg != nil {
if err := reg.Check(ctx); err != nil {
http.Error(w, "registry unreachable", http.StatusServiceUnavailable)
return
}
}
// 检查 DB(假设你把 *sql.DB 放进了 app.Context)
if db, ok := app.Get(context.Background()).(interface{ DB() *sql.DB }); ok {
if err := db.DB().PingContext(ctx); err != nil {
http.Error(w, "db unreachable", http.StatusServiceUnavailable)
return
}
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))}))
关键细节:
- 所有检查必须带
context.WithTimeout,避免 probe 卡住(K8s 默认超时 1s) - 不要在健康检查里做重操作(如查表、发 RPC),只做轻量连通性探测
- 返回非 200 时,K8s 会触发 restart;若想区分“临时不可用”和“彻底失败”,可考虑用 readinessProbe 分离语义
Helm/K8s 配置中 probe 字段怎么填
在 values.yaml 或 deployment.yaml 里,必须和代码中注册的路径、端口严格对应:
livenessProbe:
httpGet:
path: /healthz
port: http # 对应 service.port.name = "http"
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
容易踩的坑:
-
port写成数字(如8000)而不是 name(如http),会导致 probe 找不到 targetPort - 没配
initialDelaySeconds,服务还没启动完就被 probe 杀掉 - 用了 HTTPS probe 但服务只监听 HTTP,或证书配置不匹配
最后提醒一句:健康检查路径不是越复杂越好,/healthz 返回 200 是底线;加依赖检查是锦上添花,但前提是它本身足够快、足够稳——否则 probe 反而成了故障放大器。


















