Please enable Javascript to view the contents

Volcano 使用基础

 ·  ☕ 5 分钟

1. Volcano 简介

Volcano 是华为开源的一个基于 Kubernetes 的资源调度系统,相较于原生的调度器,具有的显著特点有:

  • 支持 gang scheduling

对于批量作业的调度,容易碰到死锁的问题,比如两个作业都需要同时运行 10 个 Pod 才能启动,当两个作业同时提交时,可能都只有部分 Pod 被调度,两个作业都无法正常运行,而处于互相等待状态。gang scheduling 就是为了解决这个问题。

  • 调度队列

配置不同的调度队列,能够实现对资源的抢占、配额的控制等。

  • 硬件感知

Numa、GPU 等硬件资源的感知,能够让 Pod 对硬件资源更高效的使用。

Volcano 是在 Kubernetes 原生调度能力的基础上进行的扩展和优化,因此,对于基本的 nodeSelector 、nodeAffinity 等也是支持的。同时也支持 Extended Resource,这点对于 GPU、IB 网卡等资源的在调度层面的感知非常重要。

2. 安装

  • 添加 Helm Repo
1
helm repo add volcano-sh https://volcano-sh.github.io/helm-charts
  • 安装指定版本
1
helm install volcano volcano-sh/volcano -n volcano-system --create-namespace --version 1.8.2

3. 相关 CRD 列表

1
2
3
4
5
6
7
8
9
kubectl get crd |grep volcano

commands.bus.volcano.sh              2024-03-21T03:41:33Z
jobflows.flow.volcano.sh             2024-03-21T03:41:33Z
jobs.batch.volcano.sh                2024-03-21T03:41:33Z
jobtemplates.flow.volcano.sh         2024-03-21T03:41:33Z
numatopologies.nodeinfo.volcano.sh   2024-03-21T03:41:33Z
podgroups.scheduling.volcano.sh      2024-03-21T03:41:33Z
queues.scheduling.volcano.sh         2024-03-21T03:41:33Z
  • commands.bus.volcano.sh

用于与 Volcano 系统交互。它允许用户通过创建 Command 对象来触发特定的操作,如暂停/恢复作业、重新调度等。

  • jobflows.flow.volcano.sh

JobFlow 对象描述了多个作业之间的执行依赖关系。

常见的用例是数据处理流水线,通过 Jobflow 可以自动根据依赖关系正确编排作业执行顺序。

  • jobs.batch.volcano.sh

Job 是 Volcano 最核心的资源对象,用于提交和运行批处理作业。它支持多种工作负载类型,如单个 Job、Job 数组、周期性作业等。

Job 还可以挂载数据卷、配置资源需求等。

  • jobtemplates.flow.volcano.sh

JobTemplate 为创建相似的作业提供了模板机制。用户只需定义一次作业的规格,就可以根据模板快速方便地创建多个实例。

特别适合需要同时运行数十或数百个相似作业的场景,大幅降低管理和运维成本。

  • numatopologies.nodeinfo.volcano.sh

NumaTopology 对象用于描述节点的 Numa 信息。

  • podgroups.scheduling.volcano.sh

PodGroup 对象将多个 Pod 作为一个整体进行调度。

当需要多个 Pod 同时运行时,可以使用 PodGroup 对象。

  • queues.scheduling.volcano.sh

Queue 对象用于定义作业队列,实现资源隔离和公平调度。

在多租户场景下,不同团队或部门可以根据需要创建自己专属的队列,并为队列设置资源配额和优先级参数。通过队列可以避免互相影响,实现可预测和可控的资源分配。

4. Job Pluings 定制 Pod 运行

4.1 常用的三种插件

Volcano 提供了一些内置的 plugins,如果想要自定义开发插件,需要根据源码 https://github.com/volcano-sh/volcano/tree/master/pkg/controllers/job/plugins 实现 PluginInterface 接口。下面是一个示例:

1
2
3
4
5
6
7
8
9
apiVersion: batch.volcano.sh/v1beta1
kind: Job
metadata:
  name: my-job
spec:
  plugins:
    ssh: []
    env: []
    svc: []

这些插件能够实现一些定制化的需求:

  • ssh 插件

配置 Pod 之间的 SSH 互信,提供免密登录

  • svc 插件

提供作业运行所需要的网络信息如 hosts 文件、headless service 等 ,来提供计算集群参数的自动化配置

  • env 插件

提供作业运行所需要的环境变量

4.2 注入原理

  • env 插件注入的是 VK_TASK_INDEX 、VC_TASK_INDEX。

注入原理:

1
2
3
4
5
6
7
spec:
  containers:
    - env:
        - name: VK_TASK_INDEX
          value: "0"
        - name: VC_TASK_INDEX
          value: "0"

插件从 Pod 名字中获取到索引值,然后直接设置到 env 中。

  • svc 插件注入的是 VC_DEMO_NUM、VC_DEMO_HOSTS

注入原理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
spec:
  containers:
    - env:
        - name: VC_DEMO_HOSTS
          valueFrom:
            configMapKeyRef:
              key: VC_DEMO_HOSTS
              name: my-plugins-job-svc
        - name: VC_DEMO_NUM
          valueFrom:
            configMapKeyRef:
              key: VC_DEMO_NUM
              name: my-plugins-job-svc
1
2
3
4
kubectl get cm my-plugins-job-svc

NAME                 DATA   AGE
my-plugins-job-svc   3      15m

在 my-plugins-job-svc 中存储了 VC_DEMO_NUM 和 VC_DEMO_HOSTS 的值。

  • ssh 插件注入 ssh 访问的公钥、私钥

注入原理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
spec:
  containers:
    volumes:
      - name: my-plugins-job-ssh
        secret:
          defaultMode: 384
          items:
            - key: id_rsa
              path: .ssh/id_rsa
            - key: id_rsa.pub
              path: .ssh/id_rsa.pub
            - key: authorized_keys
              path: .ssh/authorized_keys
            - key: config
              path: .ssh/config
          secretName: my-plugins-job-ssh
1
2
3
4
kubectl get secret my-plugins-job-ssh

NAME                 TYPE     DATA   AGE
my-plugins-job-ssh   Opaque   4      22m

在 my-plugins-job-ssh 中存储了 ssh 公钥和私钥,Volcano 会将秘钥挂载到 Pod 中。

4.3 测试 Plugins

  • 创建一个多个 Pod 同时运行的 Job
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cat <<EOF | kubectl apply -f -
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: my-plugins-job
spec:
  minAvailable: 3
  plugins:
    ssh: []
    env: []
    svc: []
  tasks:
    - replicas: 3
      name: demo
      template:
        spec:
          containers:
            - name: demo
              image: shaowenchen/demo-sshd
EOF

这样就创建了三个同时运行的 Pod。

  • 查看 Pod 的运行情况
1
2
3
4
5
6
kubectl get pod -o wide

NAME                            READY   STATUS    RESTARTS   AGE    IP
my-plugins-job-demo-0           1/1     Running   0          79s    10.244.228.250
my-plugins-job-demo-1           1/1     Running   0          79s    10.244.8.240
my-plugins-job-demo-2           1/1     Running   0          79s    10.244.228.249
  • 查看注入的环境变量

进入容器

1
kubectl exec -it my-plugins-job-demo-0 -- bash

打印 Volcano 注入的环境变量

1
2
3
4
5
6
env | grep -E '^VC_|^VK_'

VC_DEMO_NUM=3
VK_TASK_INDEX=0
VC_TASK_INDEX=0
VC_DEMO_HOSTS=my-plugins-job-demo-0.my-plugins-job,my-plugins-job-demo-1.my-plugins-job,my-plugins-job-demo-2.my-plugins-job

VC_DEMO_NUM 表示任务总数; VK_TASK_INDEXVC_TASK_INDEX 从源码看赋值是相等的,均表示 Task 的索引号,在每个 Pod 中各不相同,VC_DEMO_HOSTS 表示当前任务的 IP 列表。

  • 测试 ssh 免密插件

进入容器

1
kubectl exec -it my-plugins-job-demo-0 -- bash

免密 ssh 到其他 Pod

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
ssh 10.244.8.240
Warning: Permanently added '10.244.8.240' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-144-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

需要注意,这里只能通过 IP 访问,不能使用 Pod Name,因为 Volcano 并没有将其他 Pod 的 IP 和 Name 写入到 /etc/hosts 中。

5. 配置 Deployment 使用 Volcano 控制资源使用

这里举一个示例,限制 Deployment 最多仅能使用 2 核 CPU。

  • 创建队列
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cat <<EOF | kubectl apply -f -
apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
  name: my-node-queue
spec:
  weight: 1
  reclaimable: false
  capability:
    cpu: 2
EOF

创建一个仅有 2 核 CPU、并且绑定到节点组 my-node-group 的队列。

这里的 weight 表示集群资源划分中所占的相对比重,是软约束; reclaimable 表示是否允许被回收,由 weight 来决定; capability 表示队列的资源限制。

  • 创建 Deployment
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ubuntu-with-volcano
  labels:
    app: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      schedulerName: volcano
      containers:
        - name: demo
          image: shaowenchen/demo-ubuntu
          resources:
            requests:
              cpu: 1
EOF

schedulerName 设置为 volcano,表示使用 Volcano 调度器。

  • 查看 Pod
1
2
3
4
kubectl get pods -l app=demo

NAME                                  READY   STATUS    RESTARTS   AGE
ubuntu-with-volcano-97c94f9fb-bfgrh   1/1     Running   0          6m24s
  • 扩容 Deployment
1
kubectl scale deployment/ubuntu-with-volcano --replicas=3

此时,三个 Pod 只有两个处于 Running 状态,因为 Volcano 限制了 Deployment 最多仅能使用 2c CPU。

1
2
3
4
5
6
kubectl get pods -l app=demo

NAME                                  READY   STATUS    RESTARTS   AGE
ubuntu-with-volcano-97c94f9fb-25nb7   1/1     Running   0          27s
ubuntu-with-volcano-97c94f9fb-6fd64   0/1     Pending   0          27s
ubuntu-with-volcano-97c94f9fb-bfgrh   1/1     Running   0          7m31s

6. 配置 Job 使用 Volcano 限流并发执行

这里创建一个 Job 并且要求至少 3 个 Pod 一起运行的 Job。

直接使用 Kubernetes batch/v1 中的 Job ,配置 completions 和 parallelism,也可以实现这个需求。但 Volcano 提供的 Queue 可以控制资源使用、Policy 可以控制 Task 的生命周期策略,能更精准控制 Job 的执行。

  • 创建 Job
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cat <<EOF | kubectl apply -f -
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: my-job
spec:
  minAvailable: 3
  schedulerName: volcano
  queue: default
  policies:
    - event: PodEvicted
      action: RestartJob
  tasks:
    - replicas: 30
      name: demo
      policies:
      - event: TaskCompleted
        action: CompleteJob
      template:
        spec:
          containers:
            - image: ubuntu
              name: demo
              command: ["sleep", "5"]
              resources:
                requests:
                  cpu: 20
          restartPolicy: Never
EOF

其中:

1
2
3
policies:
  - event: PodEvicted
    action: RestartJob

表示如果 Pod 被 Evict 了,就重启 Job。

1
2
3
policies:
  - event: TaskCompleted
    action: CompleteJob

表示如果 Task 完成了,就完成 Job。

通过 Event 和 Action,可以控制 Job 的状态和行为。

  • 查看 Pod 创建情况
1
2
3
4
5
6
7
8
9
kubectl get pod

NAME                            READY   STATUS    RESTARTS   AGE
my-job-demo-0                   1/1     Running   0          7s
my-job-demo-1                   1/1     Running   0          7s
my-job-demo-10                  0/1     Pending   0          7s
...
my-job-demo-2                   1/1     Running   0          7s
...

由于我设置了 Pod 的 CPU Request 为 20,集群上没有足够的资源,所以 30 个 Pod 每次只能运行 3 个。

执行完成之后,Pod 不会被删除而是处于 Completed 状态。由于 Pod 的 ownerReferences 是 Job,如果删除 Job,Pod 也会被删除。


微信公众号
作者
微信公众号