Contents

解锁 Kubernetes 批处理新范式:Volcano 调度引擎初体验

https://img.lixueduan.com/kubernetes/cover/volcano-demo.png

还在为 Kubernetes 大规模批处理任务调度烦恼?Volcano——CNCF 官方批处理调度引擎,提供 Gang Scheduling、队列优先级、异构设备支持等高级特性。本文以最小化实践带你完成 Volcano 安装到验证。

1.Volcano 简介

Volcano 是什么?

官方描述:Volcano is a batch system built on Kubernetes. 基于 Kubernetes 的高性能工作负载调度引擎。

Volcano 能做什么?

支持 Kubernetes 原生负载及主流计算框架 (如TensorFlow、Spark、PyTorch、Ray、Flink等) 的一体化作业调度。

  • 强大的批处理调度能力:通过 VcJob 完美支持 Ray、TensorFlow、PyTorch、MindSpore、Spark、Flink 等主流 AI 和大数据框架

  • 完整的 Kubernetes 工作负载支持:可直接调度 Deployment、StatefulSet、Job、DaemonSet 等原生工作负载

为什么需要 Volcano?

或者说 Volcano 之前有哪些痛点。

随着各种新兴高性能计算需求的持续增长,Job 的调度和管理能力变得必要和复杂。下面罗列了一些共性需求:

  • 调度算法的多样性

  • 调度性能的高效性

  • 无缝对接主流计算框架

  • 对异构设备的支持

Volcano 正是针对这些需求应运而生的。同时,Volcano 继承了 Kubernetes 接口的设计风格和核心概念。用户可以在充分享受 Volcano 的高效性和便利性的同时不用改变任何以前使用 Kubernetes 的习惯。

场景原生 KubernetesVolcano优势
分布式任务调度Pod 独立调度Gang Scheduling (All-or-Nothing)避免死锁,提高集群利用率
资源争用处理简单 FIFO优先级队列+公平共享保障关键任务资源
GPU 调度基础设备分配拓扑感知+虚拟化提升 GPU 利用率 30%+
批量作业Job 资源限制弱作业级资源配额精准控制批量任务资源占用

现在以一个分布式训练场景为例,说明为什么需要 Volcano。

在 AI 中大规模任务比较常见,如果按照 k8s 默认的以 Pod 为单位进行调度,可能会出现资源浪费,甚至死锁的情况。

例如:启动一个 PyTorchJob 包括 1 Master 2 Worker,yaml 如下:

apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
  name: pytorch-job-example
  namespace: default
spec:
  cleanPodPolicy: None
  pytorchReplicaSpecs:
    Master:
      replicas: 1  # 主节点数量
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch/pytorch:1.9.0-cuda11.1-cudnn8-runtime
              command: ["python", "/workspace/train.py"]
              args: ["--epochs", "10"]
              resources:
                limits:
                  nvidia.com/gpu: 1  # 请求 GPU 资源
    Worker:
      replicas: 2  # Worker 节点数量
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch/pytorch:1.9.0-cuda11.1-cudnn8-runtime
              command: ["python", "/workspace/train.py"]
              args: ["--epochs", "10"]
              resources:
                limits:
                  nvidia.com/gpu: 1  # 每个 Worker 使用 1 个 GPU

按照 K8s 默认的以 Pod 为单位进行调度,可能出现只有部分 Pod 能成功调度并启动的情况,这样的结果对该 Job 来说都是无意义的。

如果有多个这样的 Job 可能都只调度了一部分 Pod,最终集群资源耗尽,所有 Job 都在等待其他 Job 释放资源。

我们需要该 Job 在调度时满足满足 Gang 调度语义,任务的所有工作负载必须全部运行或全部不运行(All or nothing),从而避免 Pod 的任意调度导致集群资源的浪费。

2. Volcano 架构

https://img.lixueduan.com/kubernetes/volcano/volcano-arch.png

可以看到 Volcano 完全构建于 Kubernetes 之上,与 Kubernetes 天然兼容,并为高性能计算而生,遵循 Kubernetes的设计理念和风格。

https://img.lixueduan.com/kubernetes/volcano/volcano-arch2.png

Volcano 包括以下组件:

  • Volcano Scheduler:通过一系列的action和plugin调度Job,并为它找到一个最适合的节点。与Kubernetes default-scheduler相比,Volcano与众不同的 地方是它支持针对Job的多种调度算法。

  • Volcano ControllerManager: Volcano controllermanager管理CRD资源的生命周期。它主要由 Queue ControllerManager、 PodGroupControllerManager、 VCJob ControllerManager构成。

  • Volcano Admission: Volcano admission 负责对 CRD API资源进行校验。

  • CRD:Job、Queue、PodGroup 等自定义资源。

  • vcctl:Volcano vcctl是Volcano的命令行客户端工具。

Volcano 通过 CRD 扩展了 K8s 对象,然后自定义 Controller 和 Scheduler 进行管理以及调度。

3. Volcano 部署

部署时需要注意 volcano 和 k8s 的版本兼容性问题,参考官方 README:Kubernetes compatibility

这里我们部署 Volcano 的 1.12.0 版本。

helm 部署

官方提供了 chart,直接使用 helm 安装即可

# 添加仓库
helm repo add volcano-sh https://volcano-sh.github.io/helm-charts

helm repo update

# 部署
helm upgrade --install volcano volcano-sh/volcano --version 1.12.0 -n volcano-system --create-namespace

验证

安装完成,验证 Volcano 组件的状态

[root@volcano ~]# kubectl get all -n volcano-system
NAME                                      READY   STATUS    RESTARTS   AGE
pod/volcano-admission-dcf9bb957-l294f     1/1     Running   0          85s
pod/volcano-controllers-bd48dd8f8-l5z9c   1/1     Running   0          85s
pod/volcano-scheduler-64f9655f97-vhk9w    1/1     Running   0          85s

NAME                                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/volcano-admission-service   ClusterIP   10.99.238.1    <none>        443/TCP    86s
service/volcano-scheduler-service   ClusterIP   10.104.54.47   <none>        8080/TCP   86s

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/volcano-admission     1/1     1            1           86s
deployment.apps/volcano-controllers   1/1     1            1           86s
deployment.apps/volcano-scheduler     1/1     1            1           86s

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/volcano-admission-dcf9bb957     1         1         1       86s
replicaset.apps/volcano-controllers-bd48dd8f8   1         1         1       86s
replicaset.apps/volcano-scheduler-64f9655f97    1         1         1       86s

查看相关 crd

[root@volcano ~]# kubectl get crd|grep volcano
commands.bus.volcano.sh                               2025-03-14T08:05:09Z
jobflows.flow.volcano.sh                              2025-03-14T08:05:09Z
jobs.batch.volcano.sh                                 2025-03-14T08:05:09Z
jobtemplates.flow.volcano.sh                          2025-03-14T08:05:09Z
numatopologies.nodeinfo.volcano.sh                    2025-03-14T08:05:09Z
podgroups.scheduling.volcano.sh                       2025-03-14T08:05:09Z
queues.scheduling.volcano.sh                          2025-03-14T08:05:09Z

4. Volcano 简单使用

接下来我们跑一个简单的 Demo 测试一下 Volcano 的能力,确认 Volcano 正确运行。

首先创建一个名为 test 的 Queue

cat <<EOF | kubectl apply -f -
apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
  name: test
spec:
  weight: 1
  reclaimable: false
  capability:
    cpu: 2
EOF

再创建一个名为job-1 的Volcano Job。

cat <<EOF | kubectl apply -f -
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: job-1
spec:
  minAvailable: 1
  schedulerName: volcano
  queue: test
  policies:
    - event: PodEvicted
      action: RestartJob
  tasks:
    - replicas: 1
      name: nginx
      policies:
      - event: TaskCompleted
        action: CompleteJob
      template:
        spec:
          containers:
            - command:
              - sleep
              - 10m
              image: nginx:latest
              name: nginx
              resources:
                requests:
                  cpu: 1
                limits:
                  cpu: 1
          restartPolicy: Never
EOF

可以看到,这个 Volcano Job 和 K8s 原生 Job 类似,不过也多了几个字段:

spec:
  minAvailable: 1
  schedulerName: volcano
  queue: test
  policies:
    - event: PodEvicted
      action: RestartJob
  • minAvailable:需要满足最小数量后才进行调度

  • schedulerName:指定调度器

  • queue:指定 Job 所属的队列,就是前面我们创建的队列

  • policies:一些特殊策略

检查 Job 的状态

kubectl get vcjob job-1 -oyaml

检查 PodGroup 的状态

kubectl get podgroup -oyaml

检查 Queue 的状态

kubectl get queue test -oyaml

最后检查 Pod 状态

[root@volcano ~]# kubectl get po
NAME            READY   STATUS              RESTARTS   AGE
job-1-nginx-0   0/1     ContainerCreating   0          24s

能够正常启动,说明 Volcano 能够正常使用,具体各个 CRD 对象的作用,后面在详细分析。

5. 小结

Volcano 是 Kubernetes 生态中一个强大的批处理调度系统,通过高级调度算法、增强的 Job 管理能力、异构设备支持和多框架集成等等,解决了 Kubernetes 在处理高性能工作负载时的局限性。

本文主要是介绍了什么是 Volcano 以及使用场景,然后通过 helm 部署 Volcano 并运行了一个最简单的 Demo。

后续详细介绍 Volcano 的各个 CRD 的作用,调度策略,以及 HAMi vGPU 和 Volcano 如何搭配使用。