1. 为什么需要滚动更新和探针配置刚接触Kubernetes时我最头疼的就是服务升级时的停机问题。记得有一次半夜做版本发布整个服务挂了将近5分钟报警短信直接把手机震到没电。后来才发现问题出在没有正确配置滚动更新策略和容器探针。Kubernetes的Deployment默认确实提供了滚动更新机制但如果不配合适当的探针配置很容易出现新Pod还没完全启动就被接入流量或者旧Pod被提前终止导致请求失败的情况。这就好比换轮胎时直接把四个轮子都拆了再装新的车子能不趴窝吗在实际生产环境中我们需要做到真正的无感知升级这意味着新版本Pod完全启动并准备好接收流量前旧Pod继续保持服务旧Pod只有在确认没有未完成请求时才会被终止整个过程中始终有足够数量的Pod在提供服务2. Deployment滚动更新策略详解2.1 基本滚动更新配置先来看一个典型的Deployment定义片段apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0这里有几个关键参数需要理解maxSurge: 更新过程中允许创建的超出期望副本数的Pod数量可以是具体数字或百分比。设置为1意味着可以比replicas多1个Pod。maxUnavailable: 更新过程中允许不可用的Pod数量。设置为0意味着必须始终保持所有Pod可用。我曾经在一个电商项目中犯过错误将maxUnavailable设置为1结果大促期间更新导致瞬间容量减少引发了短暂的服务降级。后来调整为maxSurge1和maxUnavailable0的组合更新时K8S会先启动一个新Pod等它完全就绪后再替换一个旧Pod如此循环直到全部更新完成。2.2 高级更新策略对于更复杂的场景你可能还需要考虑minReadySeconds: 新创建的Pod被认为可用前的最小就绪秒数。这个参数经常被忽视但实际上能有效避免启动即崩溃的情况。progressDeadlineSeconds: Deployment进度卡住多少秒后报告失败。默认600秒对于启动较慢的应用可能需要调大。一个经验公式是minReadySeconds应该大于你的应用平均启动时间就绪探针检测间隔。比如应用启动需要30秒就绪探针每10秒检查一次那么minReadySeconds设置为45秒比较安全。3. 容器探针的实战配置3.1 存活探针(Liveness Probe)配置存活探针用于判断容器是否在正常运行。如果探测失败kubelet会杀死容器并根据重启策略决定是否重启。一个常见的Spring Boot应用配置示例livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 10 failureThreshold: 3这里有几个坑需要注意initialDelaySeconds必须足够长确保应用完全启动。我曾经设置为30秒结果每次部署都被杀掉因为Spring Boot启动实际需要45秒。探测端点要轻量级避免影响性能。不要用需要查询数据库的接口。failureThreshold设置要合理避免网络抖动导致的误杀。3.2 就绪探针(Readiness Probe)配置就绪探针决定Pod是否可以接收流量。与存活探针不同就绪探针失败不会重启容器只是从Service的Endpoint中移除。配置示例readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 failureThreshold: 3特别提醒就绪探针的检查条件应该比存活探针更严格。比如一个需要连接数据库的应用存活探针可以只检查进程是否存在而就绪探针应该验证数据库连接是否正常。3.3 启动探针(Startup Probe)的使用对于启动特别慢的应用如Java大型应用K8S 1.16引入了启动探针startupProbe: httpGet: path: /actuator/health/startup port: 8080 failureThreshold: 30 periodSeconds: 5启动探针的特殊之处在于在启动探针成功前其他探针都会被禁用通常设置较大的failureThreshold给应用足够的启动时间启动成功后控制权会转交给存活/就绪探针4. 实现真正的零停机部署4.1 优雅终止配置即使配置了完善的探针如果不处理终止信号仍然可能出现请求丢失。K8S在删除Pod前会发送SIGTERM信号我们需要确保应用正确处理这个信号。对于Spring Boot应用可以这样配置lifecycle: preStop: exec: command: [sh, -c, sleep 15]更优雅的做法是启用Spring Boot的优雅停机功能2.3版本支持server.shutdowngraceful spring.lifecycle.timeout-per-shutdown-phase30s这样应用收到SIGTERM后停止接收新请求等待现有请求完成最长30秒关闭容器4.2 完整的部署配置示例下面是一个经过实战检验的完整Deployment配置apiVersion: apps/v1 kind: Deployment metadata: name: order-service spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 minReadySeconds: 45 template: spec: containers: - name: app image: order-service:1.2.0 ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 1 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 10 startupProbe: httpGet: path: /actuator/health/startup port: 8080 failureThreshold: 30 periodSeconds: 5 lifecycle: preStop: exec: command: [sh, -c, sleep 15]这套配置在多个生产环境中验证过能够实现真正的无感知升级。关键点在于滚动更新策略确保始终有可用实例三层探针机制覆盖应用全生命周期优雅终止处理保证请求不丢失合理的超时和等待设置适应应用特性5. 常见问题排查技巧5.1 探针调试方法当探针配置不当时可以使用这些命令排查# 查看Pod详情重点关注Conditions和Events部分 kubectl describe pod pod-name # 查看容器日志 kubectl logs pod-name -c container-name # 进入容器手动执行探针检查 kubectl exec -it pod-name -- curl http://localhost:8080/actuator/health5.2 典型问题及解决方案问题1Pod不断重启日志显示健康检查通过可能原因存活探针检测的路径太简单如只检查端口应用假死但端口仍开放解决方案增强存活探针的检查逻辑验证关键组件状态问题2更新时出现间歇性502错误可能原因就绪探针检测不够严格Pod未完全就绪就被接入流量解决方案调整就绪探针增加initialDelaySeconds或检查更多条件问题3更新耗时过长可能原因minReadySeconds设置过大或启动探针failureThreshold过高解决方案根据实际启动时间调整参数找到平衡点6. 进阶优化建议对于追求更高可用性的场景还可以考虑使用PodDisruptionBudget确保最小可用实例数配合HPA实现更新时的自动扩容采用蓝绿部署或金丝雀发布策略监控滚动更新进度和成功率记得第一次完整配置好这套机制后我们的服务升级时间从原来的几分钟降到了完全无感知。现在团队可以自信地在业务高峰期执行部署这对业务连续性和开发效率都是巨大的提升。