使用 Gang Scheduling
ACS 为作业调度场景提供了 Gang Scheduling 能力,满足作业调度场景 All-or-Nothing 需求。本文介绍如何使用 Gang Scheduling。
功能介绍
作业(Job) 一般会创建多个 Pod,并且这些 Pod 需要协调一致地启动运行。这要求在调度时一定要按照一组 Pod 分配资源,保障这一组 Pod 都可以申请到资源,或者一旦有一个 Pod 拿不到资源就认为整组 Pod 调度失败。这也就是调度器需要提供的 All-or-Nothing 调度语义,可以避免多个作业因为资源竞争出现资源维度的死锁现象。
ACS 内置的调度器提供了 Gang Scheduling 能力实现了 All-or-Nothing 语义,保障作业顺利运行。
使用方式
ACS 提供的 Gang Scheduling 兼容 Kubernetes 社区自定义资源 PodGroup,对应版本podgroups.scheduling.sigs.k8s.io/v1alpha1。您在提交每一个作业前,需要先在作业所属的命名空间下创建一个 PodGroup 实例,并在该 PodGroup 实例中声明保证作业正常运行需要的最小 Pod 个数(minMember)。之后在创建作业的 Pod 时通过设置 labels 的形式配置 pod-group.scheduling.sigs.k8s.io 关联 PodGroup 实例名字。ACS 在调度时会把使用相同 PodGroup 实例的 Pod 作为一组统一调度分配资源。
创建对应的 PodGroup 自定义资源。
apiVersion: scheduling.sigs.k8s.io/v1alpha1 kind: PodGroup metadata: name: demo-job-podgroup namespace: default spec: scheduleTimeoutSeconds: 10 minMember: 3 # 设置最小运行个数
创建一个作业,并关联 PodGroup。
apiVersion: batch/v1 kind: Job metadata: name: demo-job namespace: default spec: parallelism: 3 # Pod数量必须大于或者等于 minMember template: metadata: labels: # 关联 PodGroup 实例 demo-job-podgroup pod-group.scheduling.sigs.k8s.io: demo-job-podgroup spec: containers: - name: pi image: perl:5.34.0 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4
关联同一个 PodGroup 实例的一组 Pod 必须使用相同的优先级。
确保创建的 Pod 数量一定大于或等于 PodGroup 实例配置的 minMember。
示例
本文通过模拟资源不足场景展示 Gang Scheduling 的效果。
创建一个 Namespace,用于运行该示例。
kubectl create ns test-gang
在 Namespace 下创建 ResourceQuota,限制 Pod 的总量,模拟资源不足的情况。
cat << EOF | kubectl apply -f - apiVersion: v1 kind: ResourceQuota metadata: name: object-counts namespace: test-gang spec: hard: pods: "2" EOF
我们创建一个 Job,该 Job 期望创建 3 个 Pod,因为 ResourceQuota 限制只能运行 2 个 Pod,因此该 Job 只有两个 Pod 可以创建并运行。
cat << EOF | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: demo-job namespace: test-gang spec: parallelism: 3 # Pod数量必须大于或者等于 minMember template: spec: containers: - name: pi image: perl:5.34.0 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4 EOF
查看 Job 的 Pod 的运行状态
kubectl -n test-gang get pod
系统会输出如下信息:
NAME READY STATUS RESTARTS AGE demo-job-5kjvn 0/1 Running 0 81s demo-job-vlbkg 0/1 Running 0 80s
当使用 Gang Scheduling 时,我们期望三个 Pod 能够一起调度。如果其中一个没有创建或者没有调度成功,其他 Pod 也应该处于 Pending 状态。
在 Namespace 下创建一个 PodGroup,并设置 minMember 等于 3。
cat << EOF | kubectl apply -f - apiVersion: scheduling.sigs.k8s.io/v1alpha1 kind: PodGroup metadata: name: demo-job-podgroup namespace: test-gang spec: scheduleTimeoutSeconds: 10 minMember: 3 # 设置最小运行个数 EOF
创建一个 Job 并关联这个 PodGroup。
cat << EOF | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: demo-job namespace: test-gang spec: parallelism: 3 # Pod数量必须大于或者等于 minMember template: metadata: labels: # 关联 PodGroup 实例 demo-job-podgroup pod-group.scheduling.sigs.k8s.io: demo-job-podgroup spec: containers: - name: pi image: perl:5.34.0 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4 EOF
查看 Pod 的状态,因为此时还有 ResourceQuota 的限制,此时只能创建两个 Worker Pod,并且这两个 Pod 处于 Pending 状态。
kubectl -n test get pod NAME READY STATUS RESTARTS AGE demo-job-6wdvf 0/1 Pending 0 4s demo-job-z4jpw 0/1 Pending 0 4s
删除 ResourceQuota,解除 ResourceQuota 的限制。
kubectl -n test-gang delete resourcequota object-counts
查看 Pod 的状态,可以发现此时调度成功。
kubectl -n test-gang get pod NAME READY STATUS RESTARTS AGE demo-job-6wdvf 0/1 Running 0 29s demo-job-x7c4c 0/1 Running 0 1s demo-job-z4jpw 0/1 Running 0 29s