Go应用使用chi路由时,必须分离/healthz(存活)和/readyz(就绪)端点,推荐独立http.Server监听非业务端口(如8081),绕过chi中间件,避免阻塞、日志、鉴权等干扰,确保Kubernetes探针毫秒级准确判断状态。

chi 路由的 Go 应用必须暴露 /healthz 和 /readyz 独立端点
chi 本身不内置健康检查路径,http.ServeMux 也不自动注册 /healthz,所以你得手动加。别把 /healthz 挂在业务路由树上——比如用 r.Get("/healthz", healthHandler) 是可以的,但千万别让它经过中间件(如 JWT 验证、DB 连接池检查),否则探针一失败,整个 Pod 就被反复重启。
推荐做法是绕过 chi 路由,直接注册到 http.DefaultServeMux 或单独起一个轻量 http.Server:
func setupHealthServer() {
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
// 只检查本地状态,不查 DB、Redis、外部 API
w.WriteHeader(http.StatusOK)
w.Write([]byte("ready"))
})
go http.ListenAndServe(":8081", nil) // 单独监听 8081
}- Kubernetes 的
livenessProbe和readinessProbe应分别指向:8081/healthz和:8081/readyz - 避免复用主服务端口(如
:8080)做健康检查,防止 probe 请求挤占业务连接数 - 如果坚持用同一端口,确保 handler 不 panic、不阻塞、不依赖任何初始化未完成的资源
Deployment 中的 livenessProbe failureThreshold 别设为 1
chi 路由本身无额外开销,但 Go runtime 的 GC 停顿或偶发调度延迟可能导致单次 /healthz 响应超时。若 failureThreshold: 1,一次探测失败就触发 SIGTERM,Pod 立即重启——这会掩盖真实问题,还可能引发级联抖动。
实操建议:
- 保持默认
failureThreshold: 3,配合periodSeconds: 10和timeoutSeconds: 2 -
initialDelaySeconds至少设为 15:给 chi 路由初始化、DB 连接池 warmup、配置加载留出缓冲 - 不要在
livenessProbe里调/readyz;它只该回答“我挂了没”,不是“我能干活吗”
chi 中间件对 readinessProbe 响应时间的影响很隐蔽
常见错误是把日志中间件、请求 ID 注入、CORS、甚至 Prometheus metrics 中间件套在所有路由上,包括 /readyz。这些看似无害的操作,在高并发下会显著拖慢响应——尤其当 log.Printf 写磁盘或 metrics 更新锁竞争严重时。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
正确姿势:
- 用 chi 的
r.Mount()或独立路由树隔离健康端点,完全绕过中间件链 - 或显式跳过中间件:
r.With(noopMiddleware).Get("/readyz", readyHandler) - 本地验证方式:
kubectl port-forward pod/go-app-xxx 8081:8081,然后curl -v http://localhost:8081/readyz,观察是否稳定在
容器镜像必须禁用 CGO 并 strip 二进制
chi 本身纯 Go,但如果你用了 net/http 以外的库(比如某些 TLS 库或数据库驱动),CGO 启用会导致 Alpine 镜像运行时报 standard_init_linux.go:228: exec user process caused: no such file or directory。
构建阶段必须加编译约束:
FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . # 关键:禁用 CGO,静态链接,去掉调试符号 RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" -o main ./cmd/api
- 运行阶段用
alpine:latest或distroless/static,别用golang镜像上线 - 验证镜像是否干净:
docker run --rm -it your-image /bin/sh -c "ls -la /proc/1/exe",输出应为指向/main的符号链接,且无动态依赖(ldd main应报“not a dynamic executable”) - 不 strip 的二进制可能大 3–5MB,影响拉取速度和启动延迟,尤其在节点资源紧张时
Kubernetes 不关心你用的是 chi 还是 Gin,它只认 HTTP 探针响应和进程信号。最容易被忽略的其实是 readinessProbe 的 handler 是否真“轻量”——哪怕只多一行 log.Info("readyz hit"),在每秒几百次探测下也可能压垮日志系统。


















