下面这版是**“短期验证版”**:保留你前面“两节点异构裸机集群”的主线,但把MIG 预留方案改成NVIDIA GPU Time-Slicing,目标是:
Flyte 触发 Ray 任务 RayCluster Head 跑在 Node-1 4 个 Ray GPU Worker Pod 跑在 Node-2 每个 GPU Worker Pod 申请 nvidia.com/gpu: 1 Node-2 实际只有 1 张 RTX PRO 6000 96G 通过 Time-Slicing 暴露成 4 个可调度 GPU 份额注意:Time-Slicing 不是 MIG。它只是让多个 Pod 共享同一张物理 GPU 的时间片,没有显存隔离,也没有故障隔离;一个 Pod 把显存吃满,其他 Pod 仍可能 OOM。NVIDIA 官方也明确说明,Time-Slicing 与 MIG 的关键区别就是没有 memory / fault isolation。(NVIDIA Docs)
0. 本教程采用的当前节点信息
Node-1: 主机名:node-1 IP:192.168.1.41 角色: Kubernetes Control Plane Flyte PostgreSQL MinIO KubeRay Operator Ray Head CPU 任务 Node-2: 主机名:node-2 IP:192.168.1.42 角色: Kubernetes Worker NVIDIA GPU Operator RTX PRO 6000 96G Time-Slicing GPU Worker Pods本次最终目标:
Node-2 物理 GPU:1 张 RTX PRO 6000 96G Kubernetes 暴露: nvidia.com/gpu: 4 Ray 暴露: 4 个 GPU Worker Pod 每个 Worker Pod 有 1 个 Ray GPU Flyte 验证: Flyte task 提交 4 个 Ray remote GPU task 4 个 task 并发运行1. 为什么短期用 Time-Slicing 替代 MIG
你前面已经遇到的问题是:
MIG Mode: N/A nvidia.com/mig.capable=false vBIOS 不满足 MIG 前提所以短期不要继续追:
4 × 1g.24gb MIG改成:
1 张整卡 RTX PRO 6000 96G + Time-Slicing replicas=4Time-Slicing 的 Kubernetes 机制是:GPU Operator / NVIDIA Device Plugin 通过配置replicas,把一个真实 GPU 资源超额暴露成多个可调度资源。例如一台机器有 1 张 GPU,replicas: 4后,Kubernetes 可以看到 4 个nvidia.com/gpu。NVIDIA 官方文档也说明,Time-Slicing 配置可以通过 ConfigMap 指定replicas,并让节点暴露更多 GPU 资源。(NVIDIA Docs)
2. 最终架构图
用户 / pyflyte / flytectl | v Flyte Console / FlyteAdmin | v Flyte Task Pod | v Ray Client / Ray Job | v KubeRay RayCluster | +-- Ray Head Pod | Node-1 / 192.168.1.41 | +-- Ray GPU Worker Pod 1 | Node-2 / 192.168.1.42 | nvidia.com/gpu: 1 | +-- Ray GPU Worker Pod 2 | Node-2 / 192.168.1.42 | nvidia.com/gpu: 1 | +-- Ray GPU Worker Pod 3 | Node-2 / 192.168.1.42 | nvidia.com/gpu: 1 | +-- Ray GPU Worker Pod 4 Node-2 / 192.168.1.42 nvidia.com/gpu: 1本质上是:
4 个 Pod 共享 1 张物理 GPU 每个 Pod 拿到 1 个 Kubernetes GPU 份额 Ray 认为有 4 个 GPU worker Flyte 负责编排和提交任务3. 部署顺序总览
1. 检查当前 Kubernetes / Node / GPU 状态 2. 清理旧 MIG 期望标签 3. 给 Node-2 配置 Time-Slicing replicas=4 4. 验证 Kubernetes 是否看到 nvidia.com/gpu: 4 5. 用普通 Kubernetes Deployment 验证 4 个 GPU Pod 并发 6. 创建 KubeRay RayCluster,启动 4 个 GPU Worker Pod 7. 在 Ray Head 中验证 4 个 Ray GPU task 并发 8. 用 Flyte task 提交 Ray 任务,验证 Flyte + Ray + 4 GPU Pod 链路 9. 给出回滚和常见问题4. 预检查
4.1 检查 Kubernetes 节点
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl get nodes-owide期望看到:
node-1 Ready control-plane 192.168.1.41 node-2 Ready <none> 192.168.1.424.2 检查节点标签
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl get nodes --show-labels|grep-E'node-1|node-2'至少应该有:
node-1 有 nodepool=cpu node-2 有 nodepool=gpu node-2 有 accelerator=nvidia如果没有,执行:
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl labelnodenode-1nodepool=cpu--overwritekubectl labelnodenode-1 ray-head=true--overwritekubectl labelnodenode-1 ray-cpu=true--overwritekubectl labelnodenode-2nodepool=gpu--overwritekubectl labelnodenode-2accelerator=nvidia--overwritekubectl labelnodenode-2 ray-gpu=true--overwrite4.3 检查 Node-2 污点
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl describenodenode-2|grep-itaints-A2如果没有下面这个污点:
nvidia.com/gpu=true:NoSchedule执行:
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl taintnodenode-2 nvidia.com/gpu=true:NoSchedule--overwrite这个污点的作用是:普通 CPU Pod 不会误跑到 GPU 节点。以后需要跑到 Node-2 的 GPU Pod,都要显式写 toleration。
4.4 检查 GPU Operator
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl get pods-ngpu-operator-owide你应该看到类似组件:
nvidia-device-plugin-daemonset gpu-feature-discovery nvidia-operator-validator nvidia-container-toolkit-daemonset4.5 检查当前 GPU 资源
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl describenodenode-2|egrep-A50'Capacity|Allocatable'当前 Time-Slicing 之前,通常会看到:
nvidia.com/gpu: 1本教程完成后,目标是看到:
nvidia.com/gpu: 4Kubernetes 对 GPU 这类扩展资源的使用方式是通过 device plugin 暴露,例如nvidia.com/gpu;GPU 通常应该写在limits中,如果同时写requests和limits,两者必须相等。(Kubernetes)
5. 清理旧 MIG 期望标签
前面 MIG 方案可能曾经给 Node-2 打过:
nvidia.com/mig.config=all-1g.24gb现在短期验证 Time-Slicing,不要保留这个期望标签。
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl labelnodenode-2 nvidia.com/mig.config-||truekubectl labelnodenode-2 mig-||true重新给 Node-2 打一个更符合当前方案的标签:
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl labelnodenode-2 gpu-sharing=time-slicing-4--overwritekubectl labelnodenode-2mig=disabled-timeslicing--overwrite检查:
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl getnodenode-2 --show-labels|tr',''\n'|grep-E'gpu-sharing|mig|nodepool|accelerator'期望看到:
nodepool=gpu accelerator=nvidia gpu-sharing=time-slicing-4 mig=disabled-timeslicing6. 配置 NVIDIA GPU Time-Slicing:1 张 GPU 暴露成 4 份
这里采用节点级配置,只对 Node-2 生效。NVIDIA 官方文档支持通过 ConfigMap 定义多个 Time-Slicing 配置,并用节点标签nvidia.com/device-plugin.config=<配置名>指定某个节点使用哪份配置。(NVIDIA Docs)
6.1 创建 Time-Slicing ConfigMap
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
cat>~/gpu-timeslicing-4pods.yaml<<'EOF' apiVersion: v1 kind: ConfigMap metadata: name: gpu-timeslicing-4pods namespace: gpu-operator data: rtxpro6000-4pods: |- version: v1 flags: migStrategy: none sharing: timeSlicing: renameByDefault: false failRequestsGreaterThanOne: true resources: - name: nvidia.com/gpu replicas: 4 EOFkubectl apply-f~/gpu-timeslicing-4pods.yaml解释给小白:
replicas: 4 表示 1 张物理 GPU 暴露成 4 个 Kubernetes 可调度份额。 renameByDefault: false 表示资源名仍然叫 nvidia.com/gpu。 这样 RayCluster YAML 里继续写 nvidia.com/gpu: 1,最简单。 failRequestsGreaterThanOne: true 表示不允许 Pod 申请超过 1 个共享 GPU 份额。 因为申请 2 个 Time-Slicing GPU 份额并不代表能拿到 2 倍算力。NVIDIA 官方文档也说明,failRequestsGreaterThanOne的意义是避免用户误以为申请多个共享 GPU 份额就能获得成比例的 GPU 计算能力。(NVIDIA Docs)
6.2 让 GPU Operator 使用这个 ConfigMap
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl patch clusterpolicies.nvidia.com/cluster-policy\-ngpu-operator\--typemerge\-p'{"spec": {"devicePlugin": {"config": {"name": "gpu-timeslicing-4pods"}}}}'这里没有设置 default,意思是:
不是全局所有 GPU 节点都自动启用 只给打了 nvidia.com/device-plugin.config 标签的节点启用6.3 给 Node-2 指定 Time-Slicing 配置
【需要执行】
【执行节点:Node-1 / 192.168.1.41】
kubectl labelnodenode-2 nvidia.com/device-plugin.config=rtxpro6000-4pods