crashloopbackoff 表示 pod 容器反复崩溃并被 kubernetes 指数退避重启,根本原因包括应用崩溃、配置错误、资源不足、探针失配、依赖未就绪、镜像问题或信号处理缺失;需通过 kubectl describe 查事件、kubectl logs --previous 看崩溃日志、核对探针与优雅终止逻辑来定位。

能实现滚动更新,前提是 Deployment 配置正确、Go 应用支持优雅终止、镜像已推送到可拉取的仓库——三者缺一不可。单纯改个 image 字段却卡在 Terminating 或新 Pod 一直 CrashLoopBackOff,大概率是探针或信号处理没对上。
Deployment 必须启用 RollingUpdate 策略
Kubernetes 默认就是 RollingUpdate,但显式声明更安全,也方便调参。关键不是“能不能”,而是“怎么控速”和“容错边界”。
-
maxSurge控制新增 Pod 数量(比如25%表示最多比期望副本多启 1 个),值太小升级慢,太大可能触发资源争抢 -
maxUnavailable控制旧 Pod 可下线数量(比如25%表示最多允许 1 个 Pod 不可用),设为0能保绝对不丢请求,但升级时间拉长 - 别漏掉
minReadySeconds:新 Pod 启动后必须稳定运行多少秒才视为“就绪”,避免探针还没通就被认为可用
示例片段:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
minReadySeconds: 15
Go 应用必须响应 SIGTERM 并完成优雅关闭
滚动更新时,Kubernetes 先发 SIGTERM,等 terminationGracePeriodSeconds(默认 30s)超时再发 SIGKILL。Go 不处理 SIGTERM,就会被硬杀,正在处理的 HTTP 请求直接中断。
- 用
signal.Notify监听syscall.SIGTERM和syscall.SIGINT - 收到信号后调用
http.Server.Shutdown,传入带超时的context -
Shutdown会阻塞,等待活跃连接完成或超时,所以主 goroutine 别直接退出 - 别忘了在
Shutdown前关数据库连接、清理临时文件等收尾逻辑
关键代码节选:
server := &http.Server{Addr: ":8080", Handler: router}
go server.ListenAndServe()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
<h3>readinessProbe 和 livenessProbe 配置不当会导致更新卡住</h3>
<p>滚动更新依赖 readiness 探针判断新 Pod 是否可接入流量。如果 probe 失败,新 Pod 会一直卡在 <code>Running</code> 但 <code>NotReady</code> 状态,Deployment 就不敢删旧 Pod。</p>
-
readinessProbe的initialDelaySeconds必须大于应用启动耗时(比如加载配置、连 DB),否则 probe 过早失败,Pod 永远进不了 Ready 状态 -
livenessProbe的failureThreshold别设太低,否则偶发 GC 或慢查询可能被误判为崩溃,反复重启 - 路径要真实存在且返回 2xx:/ready 通常检查本地服务状态,/health 检查下游依赖(DB、Redis)是否连通
- 端口必须和容器
containerPort一致,且 Go 服务真正在监听该端口
典型配置:
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
更新命令要匹配容器名,且镜像 tag 必须明确
kubectl set image 是最常用的触发方式,但它要求你准确知道 Deployment 中容器的 name,而不是镜像名。
- 先确认容器名:
kubectl get deploy go-app -o jsonpath='{.spec.template.spec.containers[*].name}' - 执行更新:
kubectl set image deploy/go-app go-app=your-registry/go-app:v1.2 --record(注意中间是go-app=...,等号左边是容器名) - 镜像 tag 务必用语义化版本(如
v1.2),别用latest——Kubernetes 不会主动拉取新latest,且无法回滚 - 更新后立刻看状态:
kubectl rollout status deploy/go-app,卡住时用kubectl describe deploy/go-app查 Events
容易忽略的一点:如果你用 kubectl apply -f deploy.yaml 更新,必须确保 YAML 文件里 image 字段确实改了,GitOps 工具(如 Argo CD)也依赖这个变更检测。
滚动更新真正难的不是命令怎么敲,而是探针阈值、优雅关闭超时、资源限制这三者的协同——它们共同决定了“新旧交替”的窗口期是否足够宽裕。任何一环过紧,都会让更新过程变得脆弱甚至失败。











