startupProbe 是 Kubernetes 用于判断容器是否完成启动的探针,Go 服务只需暴露准确反映初始化完成的 HTTP 端点(如 /health/startup),并在所有关键依赖(DB、Redis、配置等)就绪后才返回 200;需用 atomic.Bool 标记状态、避免 handler 耗时操作、合理设置 failureThreshold 和超时机制,并必须配合 livenessProbe 和 readinessProbe 使用。
startupProbe 是 Kubernetes 的一个原生探针类型,用于判断容器是否完成启动。但它本身是 K8s 层面的机制,Go 程序不感知、也不需要“实现”它——你只需提供一个 HTTP 端点或命令,让 kubelet 能调用即可。真正要做的,是让 Go 服务暴露一个稳定、低开销、能准确反映“已就绪启动完成”的接口。
这个端点不是随便返回 200 OK 就行。它必须等所有关键初始化完成后再可响应,否则 K8s 可能误判并反复重启 Pod。

main() 启动后立刻监听 HTTP,应先串行执行初始化逻辑,全部成功后再启动 HTTP serversync.Once 或原子布尔值 atomic.Bool 标记“startup done”,HTTP handler 只检查该标记failureThreshold 失败func setupStartupHandler(mux *http.ServeMux, ready *atomic.Bool) {
mux.HandleFunc("/health/startup", func(w http.ResponseWriter, r *http.Request) {
if ready.Load() {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
} else {
http.Error(w, "not started", http.StatusServiceUnavailable)
}
})
}
K8s 的 startupProbe 参数稍不注意就会导致 Pod 卡在 ContainerCreating 或反复重启。
initialDelaySeconds 应设为 0 —— Go 服务启动慢,延迟探测等于主动放弃首次机会periodSeconds 建议设为 2~5,太长会导致启动失败被掩盖;太短可能压垮刚起步的服务failureThreshold 必须足够高(如 30),因为 Go 服务冷启动常需 10~20 秒(尤其带 TLS、DB 连接、证书加载)livenessProbe 共用同一个 endpoint —— startup 和 liveness 的语义不同,混合使用会让 K8s 在运行中误杀已启动成功的 PodcontainerPort 已在 Pod spec 中声明,且与 handler 绑定的端口一致,否则 kubelet 根本连不上Go 服务自身初始化过程必须有超时,否则卡死会导致 Pod 永远无法通过 startupProbe。但这个超时和 K8s 的 timeoutSeconds 是两回事:前者防程序 hang,后者防网络卡顿。
context.WithTimeout 包裹整个初始化流程,比如 initDB(ctx)、loadConfig(ctx)
failureThreshold × periodSeconds 小 5~10 秒,留出探测缓冲os.Exit(1),而不是继续启动 HTTP server —— 否则 kubelet 会一直收 503,直到 failureThreshold 耗尽,白白浪费重启配额最易被忽略的是:startupProbe 成功后,K8s 不会再调用它;但如果你没同时配好 livenessProbe 和 readinessProbe,服务后续内存泄漏或死锁将完全无人察觉。