Kubernetes GPU Deployment 没有空闲 GPU 时如何快速重启所有 Pod

Kubernetes GPU Deployment 没有空闲 GPU 时如何快速重启所有 Pod

环境和问题

环境假设:

  • Kubernetes 集群
  • Deployment 里的 Pod 申请 GPU,例如 nvidia.com/gpu: 1
  • 集群里没有空闲 GPU
  • 目标是快速重启这个 Deployment 下面的所有 Pod

这个场景里最容易踩的坑是:直接执行默认的 rollout restart 后,新 Pod 先被创建出来,但因为没有空闲 GPU 一直 Pending,旧 Pod 又还占着 GPU,结果整个重启卡住

先拿到 Deployment 的 selector

不要凭感觉手写 label。先从 Deployment 里确认它实际使用的 selector:

NS=<namespace>
DEPLOY=<deployment-name>

kubectl get deployment -n "$NS" "$DEPLOY" -o jsonpath='{.spec.selector.matchLabels}'
echo

如果输出类似:

{"app":"gpu-worker"}

后面就可以用:

kubectl get pod -n "$NS" -l app=gpu-worker

确认会命中目标 Pod:

kubectl get pod -n "$NS" -l app=gpu-worker -o wide

方法 1: 最快,直接删除 Deployment 下面的 Pod

如果可以接受这批 Pod 短暂不可用,最快方式是直接删 Pod,让 ReplicaSet 自动重建:

kubectl delete pod -n "$NS" -l app=gpu-worker

这个动作的效果是:

  1. 旧 Pod 被删除
  2. GPU 资源释放
  3. Deployment/ReplicaSet 自动创建新 Pod
  4. 新 Pod 重新申请 GPU 并调度

观察重建过程:

kubectl get pod -n "$NS" -l app=gpu-worker -w

如果只是想重启某一个 Pod,也可以指定 Pod 名:

kubectl delete pod -n "$NS" <pod-name>

方法 2: 更稳,让滚动更新先释放 GPU 再创建新 Pod

如果这是线上服务,不希望一次性删掉所有副本,建议先调整滚动策略:

kubectl patch deployment -n "$NS" "$DEPLOY" -p '{
  "spec": {
    "strategy": {
      "type": "RollingUpdate",
      "rollingUpdate": {
        "maxSurge": 0,
        "maxUnavailable": 1
      }
    }
  }
}'

然后再重启:

kubectl rollout restart deployment -n "$NS" "$DEPLOY"
kubectl rollout status deployment -n "$NS" "$DEPLOY"

这里的关键是:

  • maxSurge=0:不允许额外多创建 Pod
  • maxUnavailable=1:允许先停 1 个旧 Pod

这样可以先释放旧 Pod 占用的 GPU,再让新 Pod 调度起来

这段 patch 每个字段是什么意思

这条命令本质上是在修改 Deployment 的滚动更新策略:

kubectl patch deployment -n "$NS" "$DEPLOY" -p '{
  "spec": {
    "strategy": {
      "type": "RollingUpdate",
      "rollingUpdate": {
        "maxSurge": 0,
        "maxUnavailable": 1
      }
    }
  }
}'

逐项解释:

  • kubectl patch deployment:修改某个 Deployment 的配置
  • -n "$NS":指定 namespace
  • "$DEPLOY":指定 Deployment 名称
  • strategy.type=RollingUpdate:继续使用滚动更新,不是一次性全部停掉
  • maxSurge=0:更新过程中不允许额外多创建 Pod
  • maxUnavailable=1:更新过程中允许最多 1 个 Pod 不可用

对普通无状态服务来说,默认滚动更新通常没问题。但 GPU 满载时,默认策略可能会先创建一个新 Pod,新 Pod 需要 GPU,集群又没有空闲 GPU,于是新 Pod 一直 Pending

假设 Deployment 有 3 个 Pod,每个 Pod 用 1 张 GPU,集群刚好只有 3 张 GPU。默认策略可能变成:

先起第 4 个 Pod -> 没有 GPU -> Pending -> 旧 Pod 还占着 GPU -> 更新卡住

改成 maxSurge=0,maxUnavailable=1 后,更新顺序变成:

先停 1 个旧 Pod -> 释放 1 张 GPU -> 起 1 个新 Pod -> 新 Pod Running -> 再处理下一个

所以这段配置的核心价值是:在没有空闲 GPU 的情况下,强制 Kubernetes 先释放旧 Pod 的 GPU,再创建新 Pod,避免默认滚动更新卡在 Pending

方法 3: 全部停掉再重建

如果你明确希望所有旧 Pod 先全部退出,再统一重建,可以把策略改成 Recreate:

kubectl patch deployment -n "$NS" "$DEPLOY" -p '{
  "spec": {
    "strategy": {
      "type": "Recreate"
    }
  }
}'

再执行:

kubectl rollout restart deployment -n "$NS" "$DEPLOY"
kubectl rollout status deployment -n "$NS" "$DEPLOY"

这个方案比直接删 Pod 更有 Deployment 语义,但会造成这组副本整体短暂不可用

不建议默认使用 force delete

如果 Pod 正常退出,不要一上来就用 --force --grace-period=0

只有在 Pod 长时间卡在 Terminating,并且确认可以强制清理时,才考虑:

kubectl delete pod -n "$NS" -l app=gpu-worker --grace-period=0 --force

风险是:Kubernetes 会从 API 层面立刻删除对象,但节点上的进程不一定已经优雅退出。对 GPU 任务来说,这可能导致任务中断、显存释放延迟或日志不完整

为什么默认 rollout restart 容易卡住

默认 Deployment 策略通常允许 maxSurge,也就是先多起一个新 Pod,再逐步替换旧 Pod

普通 CPU/内存服务通常没问题,因为集群可能还有余量。但 GPU 是离散资源,没有空闲 GPU 时,新 Pod 无法调度:

0/10 nodes are available: insufficient nvidia.com/gpu

这时旧 Pod 还在 Running,新 Pod 一直 Pending,看起来像是重启没反应。根因不是 Deployment 不工作,而是新旧 Pod 的资源交接顺序不适合 GPU 满载场景

快速参考

最快重启,接受短暂不可用:

kubectl delete pod -n "$NS" -l app=gpu-worker

线上更稳的滚动重启:

kubectl patch deployment -n "$NS" "$DEPLOY" -p '{
  "spec": {
    "strategy": {
      "type": "RollingUpdate",
      "rollingUpdate": {
        "maxSurge": 0,
        "maxUnavailable": 1
      }
    }
  }
}'

kubectl rollout restart deployment -n "$NS" "$DEPLOY"
kubectl rollout status deployment -n "$NS" "$DEPLOY"

全部停掉再重建:

kubectl patch deployment -n "$NS" "$DEPLOY" -p '{
  "spec": {
    "strategy": {
      "type": "Recreate"
    }
  }
}'

kubectl rollout restart deployment -n "$NS" "$DEPLOY"

核心判断:

  • 没有空闲 GPU 时,不要直接依赖默认滚动更新
  • 想最快,删 Pod
  • 想稳一点,用 maxSurge=0,maxUnavailable=1
  • 想全量重建,用 Recreate
  • --force --grace-period=0只作为 Pod 卡死时的兜底手段
posted @ 2026-07-27 11:55  Hello_worlds  阅读(12)  评论(0)    收藏  举报