Kubernetes部署新版本后,如何确保kubectl exec进入正确Pod?
kubectl exec仍进入旧Pod的问题 问题背景
使用kubectl set image将Deployment更新至v2.0.0版本后,kubectl rollout status返回部署成功,但执行kubectl exec deploy/myapp -- show_version时,始终进入处于Terminating状态的旧v1 Pod,需等待20-30秒后才能进入新Pod执行验证。
解决方法
1. 等待旧Pod完全终止后再执行测试
kubectl rollout status仅确保新Pod就绪,不会等待旧Pod终止。可通过以下命令等待所有旧Pod被清理:
方式一:通过旧ReplicaSet等待
先获取目标Deployment的旧ReplicaSet名称:
OLD_RS=$(kubectl get rs -l app=myapp -o jsonpath='{range .items[?(@.metadata.generation!='$(kubectl get deploy myapp -o jsonpath='{.metadata.generation}')')]}{.metadata.name}{"\n"}')
等待该ReplicaSet下的所有Pod被删除:
kubectl wait --for=delete pod -l replicaset=$OLD_RS --timeout=120s
方式二:直接筛选Terminating状态的Pod
循环检查直到没有处于Terminating状态的目标Pod:
until [ $(kubectl get pods -l app=myapp --field-selector=status.phase=Terminating --no-headers | wc -l) -eq 0 ]; do sleep 2 done
2. 直接指定新Pod执行kubectl exec
跳过Deployment的随机Pod选择逻辑,直接定位到新ReplicaSet下的Pod:
先获取新Pod的名称:
NEW_POD=$(kubectl get pods -l app=myapp,pod-template-hash=$(kubectl get deploy myapp -o jsonpath='{.spec.template.metadata.labels.pod-template-hash}') -o jsonpath='{.items[0].metadata.name}')
然后执行验证命令:
kubectl exec $NEW_POD -- show_version
3. 调整Deployment的终止宽限期(可选)
如果旧Pod终止速度过慢,可以缩短terminationGracePeriodSeconds(默认30秒),让旧Pod更快被清理。修改Deployment配置:
spec: template: spec: terminationGracePeriodSeconds: 10 # 根据应用实际优雅终止需求调整
注意:需确保应用能在设定时间内完成资源释放与连接关闭,避免数据丢失或服务异常。
原因说明
kubectl rollout status的判断逻辑是:当新ReplicaSet的Pod数量达到Deployment的replicas配置,且所有新Pod处于就绪状态时,即返回部署成功。但此时旧Pod可能仍在执行终止流程(如处理剩余请求),仍属于Deployment的Pod集合,因此kubectl exec会随机选中这些未完全终止的旧Pod。
内容的提问来源于stack exchange,提问作者Marc

