iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Kubernetes

凌晨四點,女友帶著 GPU 來我家學習 Kubernetes:打造 K8s AI Infra 的 30 夜系列 第 13 篇

【Day 13】Slinky:當 HPC 的老將 Slurm 走進 Kubernetes

  • 分享至 

  • xImage
  •  

AI 模型的訓練和推論都吃 GPU,而一座 GPU 叢集要分給很多人用,這件事在雲原生的世界裡是用 Kubernetes 解的。但同樣的問題,大學和研究機構的運算中心早就遇過幾十年了。

Slurm 誕生於 2002 年,比 Kubernetes 早了十二年,處理的是同一件事:把一批運算節點分給很多人用。它從第一天就假設「一個作業要 N 個節點、跑 T 小時、全有全無」,而那正是 Kubernetes 這幾年才慢慢補上的能力。

今天的主角是 Slinky,SchedMD 自己做的一組專案,用來打通這兩個世界。


Slurm 是什麼

Slurm 是一個開源、具容錯能力、可擴展的叢集管理與作業排程系統。它做三件事:把運算節點的使用權(獨占或非獨占)在一段時間內分配給使用者;提供啟動、執行、監控平行作業的框架;用一個待處理佇列仲裁資源競爭。

架構上是中央的 slurmctld 加上每個節點的 slurmd,另有選用的 slurmdbd(記帳)與 slurmrestd(REST API)。使用者工具是 sbatch、srun、squeue、sinfo、scancel,管理工具是 scontrol。

它管理四種實體:node(運算資源)、partition(把節點分組的邏輯集合)、job(配給使用者一段時間的資源)、job step(job 內部的平行任務集合)。其中 partition 可以視為作業佇列,各自帶著作業大小上限、時間上限、允許使用的群組等限制。

GPU 這類裝置則由 GRES(Generic Resources) 插件管理。

這些名詞在 Kubernetes 那邊都找得到對應:

Slurm Kubernetes 這邊對應到的東西
partition(帶限制的作業佇列) Kueue 的 ClusterQueue
GRES nvidia.com/gpu 這類 extended resource,或 DRA
job 要 N 個節點、全有全無 Volcano 的 minAvailable、原生的 minCount
sbatch 送進佇列等 Kueue 把 Job 壓在 suspend

同一批問題,兩套答案,各自演化了很久。


Slinky 是什麼

Slinky 是 SchedMD 的一組專案,目的是讓 Slurm 和 Kubernetes 互通。兩邊的分工大致是這樣:Kubernetes 擅長排執行時間不定、資源需求可能模糊、單節點、政策寬鬆的工作,但資源池可以無限擴張;Slurm 擅長快速排定執行時間有限、資源需求與拓撲明確、跨多節點、政策嚴格的工作,但資源池是已知的。

GitHub 上的 SlinkyProject 底下有六個 repo,但重點只有兩個,而且方向剛好相反:

專案 官方的一句話
slurm-operator Run Slurm on Kubernetes
slurm-bridge Run Slurm as a Kubernetes scheduler

今天兩個都會裝。

其餘四個是支援性質的:slurm-client 是 Slurm REST API 的 Go 函式庫,供其他專案共用;containers 提供 Slurm 的容器映像;docs 是文件站的內容;slurm-exporter 則把 Slurm 的指標吐給 Prometheus。

https://ithelp.ithome.com.tw/upload/images/20260927/20183759OrIDgJm4Q6.png


實驗環境

今天在原先 fake gpu 的那台 EC2 上額外起另一個 kind 叢集 slinky-lab,一個 control-plane 加兩個 worker。所有 chart 都是 1.2.2,Slurm 版本 26.05。一樣沒有任何真的 GPU。我們會用自己的方式讓 Slurm 相信自己有卡。


讓 Slurm 相信有卡

先寫 values。這份檔案裡有四塊要同時對上,Slurm 才會認帳,我在 YAML 裡標了編號:

# slurm-values.yaml
clusterName: slinky-lab

controller:
  extraConfMap:
    GresTypes:
      - gpu                      # ① 讓 Slurm 認識 gpu 這種資源
  podSpec:
    tolerations:
      - key: slinky.slurm.net/managed-node
        operator: Exists
        effect: NoExecute

restapi:
  podSpec:
    tolerations:
      - key: slinky.slurm.net/managed-node
        operator: Exists
        effect: NoExecute

configFiles:
  gres.conf: |
    AutoDetect=off
    Name=gpu Count=3 File=/fakegpu/gpu[0-2]    # ② 卡的裝置檔在哪

nodesetDefaults:
  scalingMode: DaemonSet         # 一個 Kubernetes 節點一個 slurmd
  slurmd:
    volumeMounts:
      - name: fakegpu
        mountPath: /fakegpu
  podSpec:
    tolerations:
      - key: slinky.slurm.net/managed-node
        operator: Exists
        effect: NoExecute
    initContainers:
      - name: mkfakegpu          # ③ 真的把那些裝置檔造出來
        image: busybox:1.37
        securityContext:
          privileged: true
        command:
          - sh
          - -c
          - 'for i in 0 1 2; do [ -e /fakegpu/gpu$i ] || mknod /fakegpu/gpu$i c 195 $i; done; ls -l /fakegpu'
        volumeMounts:
          - name: fakegpu
            mountPath: /fakegpu
    volumes:
      - name: fakegpu
        emptyDir: {}

nodesets:
  gpu:
    enabled: true
    extraConfMap:
      Gres:
        - gpu:3                  # ④ 宣告這個節點有三張
    partition:
      enabled: true

partitions:
  all:
    enabled: true
    nodesets:
      - ALL
  slurm-bridge:
    enabled: true
    nodesets:
      - ALL
    configMap:
      MaxTime: UNLIMITED

① 到 ④ 缺一不可:Slurm 得先認識 gpu 這種 GRES,知道裝置檔的路徑,那些檔案要真的存在,節點也要宣告自己有幾張。

另外兩個設定等一下才會用到:scalingMode: DaemonSet 是一個 Kubernetes 節點一個 slurmd,這正是 slurm-bridge 要求的 kubelet 與 slurmd 共置;三處 tolerations 是給 bridge 待會打上的 taint 用的。


把 Slurm 裝進 Kubernetes

Slinky 的 webhook 需要憑證,所以 cert-manager 排第一個:

helm install cert-manager oci://quay.io/jetstack/charts/cert-manager \
  -n cert-manager --create-namespace --set crds.enabled=true --wait
Pulled: quay.io/jetstack/charts/cert-manager:1.21.2
NAME: cert-manager
STATUS: deployed

CRD 和 operator 是兩個 chart,順序不能換:

helm install slurm-operator-crds oci://ghcr.io/slinkyproject/charts/slurm-operator-crds \
  --version 1.2.2 --wait
Pulled: ghcr.io/slinkyproject/charts/slurm-operator-crds:1.2.2
NAME: slurm-operator-crds
STATUS: deployed
helm install slurm-operator oci://ghcr.io/slinkyproject/charts/slurm-operator \
  --version 1.2.2 -n slinky --create-namespace --wait
Pulled: ghcr.io/slinkyproject/charts/slurm-operator:1.2.2
NAME: slurm-operator
STATUS: deployed
CHART VERSION: 1.2.2
APP VERSION: 1.2.2

看它帶了哪些 CRD 進來:

kubectl get crd | grep slinky
accountings.slinky.slurm.net          2026-09-26T14:22:54Z
controllers.slinky.slurm.net          2026-09-26T14:22:54Z
loginsets.slinky.slurm.net            2026-09-26T14:22:54Z
nodesets.slinky.slurm.net             2026-09-26T14:22:54Z
restapis.slinky.slurm.net             2026-09-26T14:22:54Z
tokens.slinky.slurm.net               2026-09-26T14:22:54Z

六個。Slurm 的每個角色在 Kubernetes 上都有一個對應的物件。 controllers 是 slurmctld、nodesets 是一組同質的 slurmd worker、loginsets 是登入節點、accountings 是 slurmdbd、restapis 是 slurmrestd。

裝 Slurm 本體:

helm install slurm oci://ghcr.io/slinkyproject/charts/slurm \
  --version 1.2.2 -n slurm --create-namespace -f slurm-values.yaml
Pulled: ghcr.io/slinkyproject/charts/slurm:1.2.2
NAME: slurm
STATUS: deployed
CHART VERSION: 1.2.2
APP VERSION: 26.05
kubectl -n slurm get pods
NAME                            READY   STATUS    RESTARTS   AGE
slurm-controller-0              2/2     Running   0          5m56s
slurm-restapi-76d768f46-dn9v5   1/1     Running   0          5m56s
slurm-worker-gpu-lqxql          2/2     Running   0          5m29s
slurm-worker-gpu-q24qn          2/2     Running   0          5m29s

一個控制器、一個 REST API、兩個 worker(每個 Kubernetes worker 一個)。


Slurm 看到幾張卡

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- sinfo -o "%P %N %t %G"
PARTITION NODELIST STATE GRES
gpu slinky-lab-worker,slinky-lab-worker2 idle gpu:3
all* slinky-lab-worker,slinky-lab-worker2 idle gpu:3
slurm-bridge slinky-lab-worker,slinky-lab-worker2 idle gpu:3

兩個節點各三張,共六張。 三個 partition 是 values 裡設的,all* 的星號表示它是預設 partition。

那三張卡長什麼樣:

W=$(kubectl -n slurm get pods --no-headers | grep worker | head -1 | awk '{print $1}')
kubectl -n slurm exec $W -c slurmd -- ls -l /fakegpu
total 0
crw-r--r-- 1 root root 195, 0 Sep 26 14:24 gpu0
crw-r--r-- 1 root root 195, 1 Sep 26 14:24 gpu1
crw-r--r-- 1 root root 195, 2 Sep 26 14:24 gpu2

total 0。那三個是 mknod 造出來的字元裝置節點(c 是 character device,主編號 195 是 Linux 給 NVIDIA 的號碼),但後面什麼都沒接,就是三個空的 inode。

再確認容器裡真的什麼都沒有:

kubectl -n slurm exec $W -c slurmd -- sh -c 'ls /dev/nvidia* 2>&1 | head -3; which nvidia-smi || echo "(沒有 nvidia-smi)"'
ls: cannot access '/dev/nvidia*': No such file or directory
(沒有 nvidia-smi)

沒有裝置、沒有驅動工具,Slurm 照樣報 gpu:3。

因為 gres.conf 對 gpu 類型的 GRES 要求一定要有 File,而 Slurm 啟動時只檢查那個路徑存不存在,不會去開啟它,所以空的 inode 就夠了。

這是為了在沒有卡的機器上跑通而自己想的繞法,不是正規做法。Slinky 的正規做法是真卡加 AutoDetect=nvidia。


實驗一:Slurm 自己的全有全無

送兩個各要四張卡的 job,總共只有六張:

E="kubectl -n slurm exec slurm-controller-0 -c slurmctld --"
$E sbatch -J team-a -N2 --gres=gpu:2 --wrap="sleep 120"
$E sbatch -J team-b -N2 --gres=gpu:2 --wrap="sleep 120"
Submitted batch job 1
Submitted batch job 2

-N2 是兩個節點、--gres=gpu:2 是每節點兩張卡,所以一個 job 要四張。叢集只有六張,兩個湊不齊。

看誰上車了:

$E squeue -o "%.6i %.8j %.9T %.14b %R"
 JOBID     NAME     STATE  TRES_PER_NODE NODELIST(REASON)
     2   team-b   PENDING     gres/gpu:2 (Resources)
     1   team-a   RUNNING     gres/gpu:2 slinky-lab-worker,slinky-lab-worker2

team-a 拿到兩個節點跑起來,team-b 整個停在 PENDING,原因是 Resources。

剩下的兩張卡沒有被 team-b 拿走。它要四張,剩兩張不夠,所以一張都不拿。沒有部分配置這件事。

這不需要任何額外設定。sbatch 加 -N2 就是在說「我要兩個節點」,Slurm 的分配單位本來就是整個 job,湊不齊就整組等。

先記住 TRES_PER_NODE 這欄是 gres/gpu:2,有值。等一下會對照。

$E scancel 1 2

換個方向,讓 Slurm 來排 Kubernetes

到這裡 Slurm 跑在 Kubernetes 上了,但兩邊各過各的:Slurm 的 job 由 slurmctld 排,Kubernetes 的 Pod 由 kube-scheduler 排。

slurm-bridge 要做的是另一件事:把 Kubernetes 的工作翻譯成 Slurm job,交給 slurmctld 排。

兩個入口,一個排程器

工作可以從兩邊送進來:

從哪裡送 怎麼送
Kubernetes Pod、PodGroup、Job、JobSet、LeaderWorkerSet
Slurm salloc、sbatch

不論從哪邊進來,最後都是 slurmctld 在決定資源怎麼分。

從 Kubernetes 來的工作會經過什麼

  1. slurm-bridge 把 Pod 的資源需求翻譯成一個對應的 Slurm job
  2. 這個 job 以 external job 的身分進入 Slurm,由 slurmctld 排定
  3. 排定之後,slurm-bridge 把 Pod 綁到 Slurm 分配到的節點上
  4. 接下來 kubelet 照常啟動 Pod,和一般的 Pod 沒有差別

所以 Pod 還是 Pod,只是「放到哪個節點」這個決定被移到 Slurm 那邊做了。

一條限制:節點不能同時跑兩種使用者工作

混合節點上的硬體是分時共用的。一台實體節點不能同時跑原生 Slurm 的使用者工作和 bridge 管理的 Kubernetes 使用者工作,只有兩邊的系統 daemon 可以共存在同一台機器上。

先發通行證

slurm-bridge 會在它管的節點上打 NoExecute taint。有五個元件是 slurm-values.yaml 管不到的,先補 toleration:

for x in cert-manager/cert-manager cert-manager/cert-manager-webhook cert-manager/cert-manager-cainjector slinky/slurm-operator slinky/slurm-operator-webhook; do
  ns=${x%%/*}; d=${x##*/}
  kubectl -n $ns patch deploy $d --type=json -p \
    '[{"op":"add","path":"/spec/template/spec/tolerations","value":[{"key":"slinky.slurm.net/managed-node","operator":"Exists","effect":"NoExecute"}]}]' \
    && echo "patched $x"
done
deployment.apps/cert-manager patched
patched cert-manager/cert-manager
deployment.apps/cert-manager-webhook patched
patched cert-manager/cert-manager-webhook
deployment.apps/cert-manager-cainjector patched
patched cert-manager/cert-manager-cainjector
deployment.apps/slurm-operator patched
patched slinky/slurm-operator
deployment.apps/slurm-operator-webhook patched
patched slinky/slurm-operator-webhook

建 namespace 並取得 token

kubectl create namespace slurm-bridge
kubectl create namespace demo

demo 這個名字是刻意的。chart 的 admission.managedNamespaces 預設就是 slurm-bridge 自己,而那正是它的 webhook 會排除掉的 namespace,所以照預設裝完,什麼都不會被接管。

bridge 要用 REST API 跟 Slurm 說話(走的就是 Slinky 的 slurm-client 函式庫),所以先跟 Slurm 要一個 token:

JWT=$(kubectl -n slurm exec slurm-controller-0 -c slurmctld -- \
        scontrol token username=root lifespan=31536000 | sed 's/^SLURM_JWT=//' | tr -d '\r\n')
kubectl -n slurm-bridge create secret generic slurm-bridge-token --from-literal=auth-token="$JWT"
secret/slurm-bridge-token created
helm install slurm-bridge oci://ghcr.io/slinkyproject/charts/slurm-bridge \
  --version 1.2.2 -n slurm-bridge \
  --set-json 'admission.managedNamespaces=["demo"]'
Pulled: ghcr.io/slinkyproject/charts/slurm-bridge:1.2.2
NAME: slurm-bridge
STATUS: deployed

它把自己鎖在門外了

kubectl -n slurm-bridge get pods
NAME                                        READY   STATUS      RESTARTS   AGE
slurm-bridge-admission-59b67b97f4-97hq6     0/1     Pending     0          2s
slurm-bridge-controllers-5fb6bd798f-4j6d8   0/1     Completed   0          12s
slurm-bridge-controllers-5fb6bd798f-npgqv   0/1     Pending     0          2s
slurm-bridge-scheduler-5c974578f8-8pxdn     0/1     Pending     0          2s

helm 說 deployed,但三個元件都沒起來。那個 Completed 是它在 taint 打上去之前就排到節點上,然後被趕下來的。

kubectl get nodes -o custom-columns='NODE:.metadata.name,TAINTS:.spec.taints[*].key'
NODE                       TAINTS
slinky-lab-control-plane   node-role.kubernetes.io/control-plane
slinky-lab-worker          slinky.slurm.net/managed-node
slinky-lab-worker2         slinky.slurm.net/managed-node

兩個 worker 被 bridge 打了 taint,control-plane 有內建的,而 chart 預設兩個都不容忍。把它們釘到 control-plane 上:

for d in slurm-bridge-admission slurm-bridge-controllers slurm-bridge-scheduler; do
  kubectl -n slurm-bridge patch deploy $d --type=json -p '[
    {"op":"add","path":"/spec/template/spec/nodeSelector","value":{"node-role.kubernetes.io/control-plane":""}},
    {"op":"add","path":"/spec/template/spec/tolerations","value":[
      {"key":"node-role.kubernetes.io/control-plane","operator":"Exists","effect":"NoSchedule"},
      {"key":"slinky.slurm.net/managed-node","operator":"Exists","effect":"NoExecute"}]}
  ]' && echo "patched $d"
done
deployment.apps/slurm-bridge-admission patched
patched slurm-bridge-admission
deployment.apps/slurm-bridge-controllers patched
patched slurm-bridge-controllers
deployment.apps/slurm-bridge-scheduler patched
patched slurm-bridge-scheduler
kubectl -n slurm-bridge get pods -o wide | awk '{print $1,$2,$3,$7}'
NAME READY STATUS NODE
slurm-bridge-admission-599467d9cc-jb8w2 1/1 Running slinky-lab-control-plane
slurm-bridge-controllers-75b8ff9484-h6lqs 1/1 Running slinky-lab-control-plane
slurm-bridge-scheduler-74b5d48749-4rb5v 1/1 Running slinky-lab-control-plane

實驗二:一個普通的 Pod,被 Slurm 排走了

開一個什麼都沒寫的 Pod,沒有 schedulerName、沒有 annotation、沒有 label:

kubectl -n demo apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: plain, namespace: demo}
spec:
  restartPolicy: Never
  containers:
    - name: c
      image: busybox:1.37
      command: ["sh","-c","sleep 300"]
      resources: {limits: {cpu: "1", memory: 256Mi}}
EOF
kubectl -n demo get pod plain -o custom-columns='NAME:.metadata.name,SCHED:.spec.schedulerName,PHASE:.status.phase,NODE:.spec.nodeName'
NAME    SCHED                    PHASE     NODE
plain   slurm-bridge-scheduler   Running   slinky-lab-worker

schedulerName 是 admission webhook 改上去的,因為這個 Pod 落在 managedNamespaces 裡的 demo。在沒被管理的 namespace 裡,自己寫 schedulerName: slurm-bridge-scheduler 一樣有效。

那它在 Slurm 那邊看得到嗎:

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- squeue -o "%.6i %.10j %.9T %.12P %.14b %R"
 JOBID       NAME     STATE    PARTITION  TRES_PER_NODE NODELIST(REASON)
     3     (null)   RUNNING slurm-bridge            N/A slinky-lab-worker

一個 Kubernetes Pod 出現在 squeue 裡。 名字是 (null),因為它沒有 Slurm job name。

注意 TRES_PER_NODE 是 N/A,對照實驗一的 gres/gpu:2。這個 Pod 沒有帶任何 GRES 需求進來,它本來就沒要 GPU。要把 GRES 傳過去有兩條路:用 slurmjob.slinky.slurm.net/ 前綴的 annotation 指定,或是用 DRA 的 DeviceClass 資源名稱請求裝置。兩條這次都沒走。

看它在 Slurm 帳上的細節:

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- scontrol show job 3 | grep -E "ReqTRES|AllocTRES"
   ReqTRES=cpu=1,mem=256M,node=1,billing=1
   AllocTRES=cpu=8,mem=256M,node=1,billing=8

Pod 要 1 顆 CPU,Slurm 給了整台 8 顆。 這不是計算錯誤,是 slurm-bridge 的預設行為:它把 Pod 翻譯成 Slurm job 時,要的是整個節點的獨占使用權,而不是 Pod 寫的那點資源。


實驗三:一個 Pod 吃掉一整台機器

上一個實驗那條規則的後果馬上就看得到。再放一個 Pod 佔住另一台,然後從 Slurm 側送一個要吃光所有卡的 job:

kubectl -n demo apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata: {name: plain2, namespace: demo}
spec:
  restartPolicy: Never
  containers:
    - name: c
      image: busybox:1.37
      command: ["sh","-c","sleep 300"]
      resources: {limits: {cpu: "1", memory: 256Mi}}
EOF

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- sbatch -J hpc-hog -N2 --gres=gpu:3 --wrap="sleep 120"
Submitted batch job 5
kubectl -n slurm exec slurm-controller-0 -c slurmctld -- squeue -o "%.6i %.10j %.9T %.12P %R"
 JOBID       NAME     STATE    PARTITION NODELIST(REASON)
     5    hpc-hog   PENDING          all (Resources)
     4     (null)   RUNNING slurm-bridge slinky-lab-worker2
     3     (null)   RUNNING slurm-bridge slinky-lab-worker

HPC 的 job 排在兩個 Kubernetes Pod 後面,因為它們現在在同一個佇列裡。

但要看清楚阻塞的原因:不是在搶卡,那兩個 Pod 根本沒要 GPU。是它們各獨占了一整個節點,所以要兩個節點的 hpc-hog 無處可去。

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- scancel 5

實驗四:一行 annotation,從整台變成兩顆

開一個「願意共享」的 Pod,和前兩個唯一的差別是那行 annotation:

kubectl -n demo apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: shared
  namespace: demo
  annotations:
    slurmjob.slinky.slurm.net/exclusive: "false"
spec:
  restartPolicy: Never
  containers:
    - name: c
      image: busybox:1.37
      command: ["sh","-c","sleep 300"]
      resources: {limits: {cpu: "1", memory: 256Mi}}
EOF
kubectl -n demo get pods -o custom-columns='NAME:.metadata.name,PHASE:.status.phase,NODE:.spec.nodeName'
NAME     PHASE     NODE
plain    Running   slinky-lab-worker
plain2   Running   slinky-lab-worker2
shared   Pending   <none>

願意共享的那個反而進不去,因為兩台都被前面兩個獨占了。獨占會傳染。

放掉一台:

kubectl -n demo delete pod plain2 --wait=true
kubectl -n demo get pods -o custom-columns='NAME:.metadata.name,PHASE:.status.phase,NODE:.spec.nodeName'
NAME     PHASE       NODE
plain    Succeeded   slinky-lab-worker
shared   Running     slinky-lab-worker

(plain 顯示 Succeeded 是 sleep 300 自然跑完了。)

kubectl -n slurm exec slurm-controller-0 -c slurmctld -- scontrol show job 6 | grep -E "JobState|ReqTRES|AllocTRES"
   JobState=RUNNING Reason=None Dependency=(null)
   ReqTRES=cpu=1,mem=256M,node=1,billing=1
   AllocTRES=cpu=2,mem=256M,node=1,billing=2

AllocTRES 從 cpu=8 變成 cpu=2,annotation 有效。

是 2 不是 1,因為這個節點的 ThreadsPerCore=2,Slurm 配的是核心,不是執行緒。

這行 annotation 背後的機制是 MCS:非獨占的工作會以 Shared=mcs 加上設定好的 MCS label 送出,讓同一個 MCS 類別的 bridge 工作可以共用節點,而原生的 Slurm job 進不來。不過這需要兩邊都設定才會生效,bridge 這側要在 values 裡指定 schedulerConfig.mcsLabel,Slurm 那側要在 slurm.conf 加上 MCSPlugin=mcs/label 與 MCSParameters=ondemand,ondemandselect。本篇兩項都沒設,所以只驗到「不獨占」這一個效果。


小結

今天做了兩件方向相反的事。

slurm-operator 把 Slurm 搬進 Kubernetes:六個 CRD、一份 values,Slurm 的控制器、REST API、worker 全部變成 Pod。這和昨天的 KubeRay 是同一種形狀:把一個既有的分散式系統交給 operator 管生命週期。

slurm-bridge 把方向倒過來:一個沒寫任何特殊欄位的 Pod,schedulerName 被 webhook 改成 slurm-bridge-scheduler,然後出現在 squeue 裡,由 slurmctld 決定它去哪台機器。排程器本身被換掉了,換成一個比 Kubernetes 還老的 HPC 排程器。

兩個實驗結果值得記住。

一是實驗一:兩個各要四張卡的 job、只有六張,結果一個跑一個等,沒有部分配置。Slurm 不需要 gang 這個功能,因為它的模型本來就是這樣。

二是實驗二和三:一個只要 1 顆 CPU 的 Pod,在 Slurm 帳上佔了整台機器的 8 顆,還把一個 HPC job 擋在外面。Kubernetes 的習慣是把節點塞滿,Slurm 的習慣是整節點配給一個 job。兩邊的預設假設剛好相反,而接起來之後,Kubernetes 的 Pod 要照 Slurm 的規矩走。


參考資料

Slurm — Overview
Slurm — Slinky
Slurm — gres.conf
SlinkyProject/slurm-operator
SlinkyProject/slurm-bridge
slurm-bridge — Configuration
slurm-bridge — Quickstart
Slurm - Nvidia developer


上一篇
【Day 12】KubeRay:當 Kubernetes 轉角遇見 Ray
下一篇
【Day 14】GPU 高效能網路:從節點內到跨節點,再到 Kubernetes
系列文
凌晨四點,女友帶著 GPU 來我家學習 Kubernetes:打造 K8s AI Infra 的 30 夜 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言