/healthz应仅暴露给主Go容器,由其独立提供;sidecar不暴露业务健康端点,探针必须明确指向主容器的监听端口,避免跨容器误用或共用。

多容器Pod里,/healthz该暴露给谁?
多容器Pod(比如主应用 + sidecar)中,livenessProbe 和 readinessProbe 默认作用于整个容器组,但探针实际只打到某一个容器的端口。如果你在主 Go 容器里暴露了 /healthz,却把探针配在 sidecar 容器上,或者反过来——探针永远 404 或连接拒绝。
必须明确:Kubernetes 的 HTTP 探针不跨容器;它只访问你指定容器的 port 和 path。Sidecar(如 istio-proxy、envoy、log-forwarder)一般不提供业务健康端点,也不该承担主服务的就绪判断。
- 只在主 Go 容器中启动
http.ListenAndServe并注册/healthz,sidecar 不暴露任何 HTTP 健康接口 - 所有探针的
httpGet.port必须指向主容器的监听端口(不是 sidecar 的 admin 端口) - 如果 sidecar 自身需要健康检查(如 istio-proxy 的
/ready),那是它自己的事,由它自己处理,不应和主服务探针混用或共用 handler
init 容器跑完后,Go 主容器的 readinessProbe 为什么还失败?
常见现象:initContainers 已成功退出,kubectl get pod 显示 Init:0/1 变成 Running,但 Pod 长时间卡在 NotReady,describe 显示 ContainersReady=False,原因是 readinessProbe 持续返回非 200。
根本原因不是探针配置错,而是 Go 主容器还没真正“准备好”——比如它在初始化 DB 连接、加载配置文件、等待上游服务响应,而 readinessProbe 已经开始执行,且超时或检查失败。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
initialDelaySeconds必须 ≥ init 容器耗时 + Go 主容器冷启动耗时(建议留出 buffer,比如 init 耗时 8s,Go 初始化平均 12s,则设为 25s) - 不要让 readinessProbe 检查下游依赖(如 DB、Redis)时使用长超时;改用
db.PingContext(ctx, 1*time.Second),避免 probe 卡住整个就绪流程 - 若主容器依赖 init 容器输出(如写入 config 文件),确保 Go 代码在 handler 中做了存在性校验,而不是直接 panic 或静默失败
sidecar 和主容器共享 readiness,会导致滚动更新卡死
有人为了“简化”,把主容器和 sidecar 的 readinessProbe 都指向同一个 /healthz 端点,甚至让 sidecar 反向代理该路径。结果是:sidecar 启动慢、升级滞后,或某次重启失败,导致整个 Pod 的 readiness 一直不通过,Deployment 卡在“旧副本未下线、新副本无法就绪”的僵局。
Kubernetes 的 Endpoint Controller 只看 Pod 的整体 Ready 状态,而这个状态取决于所有容器的 readinessProbe 全部通过。只要有一个容器 probe 失败,Endpoint 就不会包含该 Pod IP。
- sidecar 容器应使用独立、轻量、自包含的 readiness 探针(如
exec: ["sh", "-c", "curl -f http://localhost:15021/healthz/ready"]对应 istio-proxy) - 主 Go 容器的 readinessProbe 只检查自身状态(原子变量
isReady)、本地缓存、必要依赖,绝不依赖 sidecar 的健康结果 - 避免在 Go handler 中调用 localhost 的 sidecar 端口(如
http://localhost:15090)做检查——这引入隐式耦合,且网络栈在 Pod 内虽通,但时序不可控
多个 Go 容器共存时,端口冲突和 probe 目标混淆
一个 Pod 里跑两个 Go 容器(比如 api-server + metrics-exporter),都监听 8080,又都配了 httpGet.path: /healthz,结果探针总打到错的容器上,或者因端口冲突直接启动失败。
根本问题在于:Kubernetes 不支持“按容器名路由探针”,只认 containerPort 和 targetPort 的绑定关系。如果两个容器声明了相同的 containerPort: 8080,kubelet 会报错或随机覆盖。
- 每个 Go 容器必须使用不同监听端口(如
8080和9090),并在ports列表中显式声明name(如name: http/name: metrics) - 对应探针的
httpGet.port必须填数字端口或 port name(推荐 name,更可读),不能只靠顺序猜测 - 若用
exec探针替代 HTTP,注意命令运行环境是容器内部 shell,curl localhost:8080/healthz仍可能打错目标——因为 localhost 在容器内指本容器,不是 Pod 网络命名空间
最容易被忽略的一点:多容器 Pod 的健康逻辑不是“加法”,而是“与运算”。任何一个容器 probe 失败,整个 Pod 就不可用。别指望靠 sidecar 的健壮性来兜底主服务的缺陷,也别把主服务的延迟初始化压力转嫁给 sidecar 的探针周期。

















