本文介紹了Slurm HPC與Kubernetes融合的負載調度策略,旨在通過最佳化資源配置與作業調度機制,不僅能提升計算資源的利用率,還增強了系統整體的穩定性和運行效能。此方案確保在滿足多種計算情境需求的同時,為您構建一個更為高效且靈活的計算平台。
方案概述
為什麼要提出在ACK叢集上實現Slurm HPC & Kubernetes負載混合調度呢?
原因分析:目前ACK會提供靜態分配+分離調度的方案,但是由於每個Slurm Pod的規格固定,且Slurm Pod屬於提前佔用叢集資源,Slurm叢集中資源空閑時Kubernetes無法使用這些已佔用的叢集資源,從而導致叢集資源片段。此外,修改Slurm Pod的資源規格需要刪除Pod重建,因此在Slurm與Kubernetes資源佔用變化較大的情境中,節點遷移的難度較大。
改進方案:考慮到現有方案的弊端,ACK Slurm Operator提供一種Slurm & Kubernetes混合調度方案,通過配置運行在Kubernetes叢集中的協調器以及Slurm叢集的擴充資源外掛程式,使得Kubernetes與Slurm可以共用叢集資源,並且避免在分配資源時出現重複分配的情況。
目前任務共用資源方案可以分為以下兩種。
靜態分配 + 分離調度 | Slurm HPC + Kubernetes負載混合調度 |
Slurm HPC + Kubernetes負載混合調度方案的運行原理如下圖所示。

核心組件 | 描述 |
SlurmOperator | 負責在叢集中以容器化形式拉起Slurm叢集。叢集會以容器化的方式運行,運行Slurm的Worker Pod會以互斥的方式運行在不同叢集節點上,其他的Slurm系統組件會隨機運行在叢集節點上。 |
SlurmCopilot | 使用叢集Token(預設啟動Slurmctld時會自動產生Token並通過kubectl更新到secret中,可通過自訂啟動指令碼或取消更新secret許可權修改此行為,修改後需要手動更新Token至ack-slurm-operator空間下的ack-slurm-jwt-token,Data中以ClusterName為Key,以Token base64 --wrap=0後的結果為value)與Slurmctld進行資源協調通訊。負責在AdmissionCheck被添加到GenericNode上後,修改Slurmctld中對應節點的可用資源量,成功修改可用資源量後將狀態寫回GenericNode,通知ACK Scheduler完成調度。 |
Slurmctld | slurm的中心管理器,負責監測叢集的資源和作業,以及進行作業的調度和分配。為了提高可用性,還可以配置一個備份的slurmctld。 |
GenericNodes | 是一種自訂資源,作為Kubernetes和Slurm的中間賬本。ACK Scheduler調度一個Pod到節點上之前,會在GenericNode上新增AdmissionCheck,請求Slurm系統確認資源。 |
Slurmd | slurm的節點守護進程,運行在每個計算節點上,負責執行作業,以及向slurmctld彙報節點和作業的狀態。 |
Slurmdbd | slurm的資料庫守護進程,負責儲存和管理作業的記賬資訊,以及提供查詢和統計的介面。slurmdbd是可選的,也可以將記賬資訊儲存在檔案中。 |
Slurmrested | slurm的REST API守護進程,提供了一種通過REST API與slurm進行互動的方式,可以實現slurm的所有功能。slurmrestd是可選的,也可以通過命令列工具與slurm進行互動。 |
1. 環境準備
1.1 安裝ack-slurm-operator組件
確認已安裝的ACK叢集版本為v1.26及以上。具體操作,請參見為叢集添加GPU節點、升級叢集。
安裝ack-slurm-operator組件並開啟Copilot功能,實現Slurm任務與Kubernetes Pod在同一批物理機器上混合部署。
登入Container Service管理主控台。單擊目的地組群名稱,進入叢集詳情頁面,如下圖所示,按照序號依次單擊,為目的地組群安裝ack-slurm-operator組件。
您無需為組件配置應用程式名稱和命名空間,單擊④下一步後會出現一個請確認的彈框,單擊是,即可使用預設的應用程式名稱(ack-slurm-operator)和命名空間(ack-slurm-operator)。

然後選擇Chart 版本為最新版本,並將②參數
enableCopilot設定為true,將③參數watchNamespace設定為default(您也可以根據需要自主設定命名空間),單擊確定即可完成ack-slurm-operator組件安裝。
(可選)更新ack-slurm-operator組件操作步驟。
登入Container Service管理主控台。在叢集資訊頁面,單擊應用 > Helm頁簽,在應用頁面找到ack-slurm-operator組件,然後點擊更新。

1.2 安裝配置ack-slurm-cluster組件
如需快速安裝、管理SlurmCluster,以及靈活調整叢集配置,您可以使用Helm軟體包管理器來部署阿里雲提供的SlurmCluster。從charts-incubator中下載由阿里雲封裝好的SlurmCluster的Helm,設定好相應的參數後,Helm會協助您建立出RBAC、ConfigMap、Secret以及SlurmCluster等資源。
具體操作如下所示:
執行以下命令,將阿里雲Helm倉庫添加到您的Helm用戶端。該操作將允許您訪問阿里雲提供的各種Charts,包括ack-slurm-cluster組件。
helm repo add aliyun https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts-incubator/執行以下命令,拉取並解壓ack-slurm-cluster組件。該操作將會在目前的目錄下建立一個名為
ack-slurm-cluster的目錄,其中包含了Chart的所有檔案和模板。helm pull aliyun/ack-slurm-cluster --untar=true執行以下命令,在名為values.yaml的檔案中修改Chart參數。
values.yaml檔案包含了Chart的預設配置。您可以根據您的實際需求通過編輯這個檔案來修改參數。例如Slurm的配置、資源請求與限制、儲存等。
cd ack-slurm-cluster vi values.yaml使用Helm安裝Chart,執行以下命令將會部署ack-slurm-cluster組件。(如果已經安裝了ack-slurm-cluster,可以使用helm upgrade命令更新helm chart。更新後需要手動清理已有Pod以及Slurmctld的StatefulSet完成配置更新。)
cd .. helm install my-slurm-cluster ack-slurm-cluster # my-slurm-cluster可以根據實際情況變更。通過Helm安裝之後可以通過
helm list查看當前的ack-slurm-cluster是否完成安裝。helm list預期輸出結果如下。
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION ack-slurm-cluster default 1 2024-07-19 14:47:58.126357 +0800 CST deployed ack-slurm-cluster-2.0.0 2.0.0驗證Slurmrestd & Slurmdbd正常啟動
通過kubectl串連叢集查看slurmdbd Pod是否正常啟動。
kubectl get pod預期輸出結果如下,可以看到此時叢集中有1個Worker節點和3個控制面組件的Pod。
NAME READY STATUS RESTARTS AGE slurm-test-slurmctld-dlncz 1/1 Running 0 3h49m slurm-test-slurmdbd-8f75r 1/1 Running 0 3h49m slurm-test-slurmrestd-mjdzt 1/1 Running 0 3h49m slurm-test-worker-cpu-0 1/1 Running 0 166m執行以下命令查看日誌資訊,瞭解Slurmdbd是否已經正常啟動。
kubectl exec slurm-test-slurmdbd-8f75r cat /var/log/slurmdbd.log | head預期輸出結果如下。
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. [2024-07-22T19:52:55.727] accounting_storage/as_mysql: _check_mysql_concat_is_sane: MySQL server version is: 8.0.34 [2024-07-22T19:52:55.737] error: Database settings not recommended values: innodb_lock_wait_timeout [2024-07-22T19:52:56.089] slurmdbd version 23.02.7 started
如果您需要在Slurm中擴充安裝其他依賴軟體,您可以展開查看下述內容。
2. 驗證拓展負載混合調度功能
2.1 驗證負載混合調度功能
查看genericnode狀態,可以看到Slurm與Kubernetes的負載狀態。
kubectl get genericnode預期輸出結果如下。
NAME CLUSTERNAME ALIAS TYPE ALLOCATEDRESOURCES cn-hongkong.10.1.0.19 slurm-test-worker-cpu-0 Slurm [{"allocated":{"cpu":"0","memory":"0"},"type":"Slurm"},{"allocated":{"cpu":"1735m","memory":"2393Mi"},"type":"Kubernetes"}]提交一個任務到Slurm叢集中,相關命令和預期輸出結果如下,可以看到Kubernetes的任務和Slurm的任務資源使用量都反映在了GenericNode上。
root@iZj6c1wf3c25dbynbna3qgZ ~]# kubectl exec slurm-test-slurmctld-dlncz -- nohup srun --cpus-per-task=3 --mem=4000 --gres=k8scpu:3,k8smemory:4000 sleep inf & [1] 4132674 [root@iZj6c1wf3c25dbynbna3qgZ ~]# kubectl scale deployment nginx-deployment-basic --replicas 2 deployment.apps/nginx-deployment-basic scaled [root@iZj6c1wf3c25dbynbna3qgZ ~]# kubectl get genericnode NAME CLUSTERNAME ALIAS TYPE ALLOCATEDRESOURCES cn-hongkong.10.1.0.19 slurm-test-worker-cpu-0 Slurm [{"allocated":{"cpu":"3","memory":"4000Mi"},"type":"Slurm"},{"allocated":{"cpu":"2735m","memory":"3417Mi"},"type":"Kubernetes"}]此時再提交一個任務到Slurm叢集中,可以看到第2個提交的任務進入了PD(Pending)狀態。
[root@iZj6c1wf3c25dbynbna3qgZ ~]# kubectl exec slurm-test-slurmctld-dlncz -- nohup srun --cpus-per-task=3 --mem=4000 sleep inf & [2] 4133454 [root@iZj6c1wf3c25dbynbna3qgZ ~]# srun: job 2 queued and waiting for resources [root@iZj6c1wf3c25dbynbna3qgZ ~]# kubectl exec slurm-test-slurmctld-dlncz -- squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 2 debug sleep root PD 0:00 1 (Resources) 1 debug sleep root R 2:34 1 slurm-test-worker-cpu-0
在上述的srun的樣本中,我們並沒有指定gres擴充資源,這是由於在slurm叢集啟動時已經載入了job_resource_completion外掛程式,該外掛程式會自動根據cpu和mem的請求量產生對應的gres資源量。如果沒有開啟該外掛程式,您需要手動指定,本例中需要指定的額外參數為--gres=k8scpu:3,k8smemory:4000。如果您需要瞭解關於Slurm任務指令碼參數是如何設定的,您可以展開查看下述內容。
(可選)2.2 拓展混合調度功能-非容器化Slurm叢集
由於SlurmCopilot通過Slurm的OpenAPI與Slurm進行互動,所以在非容器化情境中,SlurmCopilot同樣可以使用。
針對非容器化情境,Kubernetes中的部分資源需要手動進行建立,除上文中可能需要手動建立的Token之外,需要手動建立的資源如下。
為每個SlurmCluster建立SVC。
SlurmCopilot會從叢集中擷取Service資訊,並向
${.metadata.name}.${.metadata.namespace}.svc.cluster.local:${.spec.ports[0].port}發出OpenAPI請求,在非容器化情境中,需要為每個SlurmCluster建立對應的SVC,樣本如下,必須要注意的是SVC的Name必須是${slurmCluster}-slurmrestd,該${slurmCluster}需要能夠與GenericNode中相對應。apiVersion: v1 kind: Service metadata: name: slurm-slurmrestd namespace: default spec: ports: - name: slurmrestd port: 8080 protocol: TCP targetPort: 8080為每個SlurmCluster建立DNS解析。
為了能訪問到對應的Slurmrestd進程,需要在SlurmCopilot中建立對
${.metadata.name}.${.metadata.namespace}.svc.cluster.local:${.spec.ports[0].port}的位址解析,解析結果為Slurmrestd的進程地址。Slurm節點對應的GenericNode資源。
GenericNode用於給SlurmCopilot提供節點在Slurm叢集內的別名,否則SlurmCopilot將無法擷取到Slurm中該節點的具體資訊。其中GenericNode的Name必須與Kubernetes的節點名對應,
.spec.alias必須與Slurm中該節點的命名對應,而標籤中的kai.alibabacloud.com/cluster-name以及kai.alibabacloud.com/cluster-namespace需要與SVC的資訊對應。apiVersion: kai.alibabacloud.com/v1alpha1 kind: GenericNode metadata: labels: kai.alibabacloud.com/cluster-name: slurm-test kai.alibabacloud.com/cluster-namespace: default name: cn-hongkong.10.1.0.19 spec: alias: slurm-test-worker-cpu-0 type: Slurm
總結
在Slurm HPC和容器化工作負載的混合調度環境中,使用Slurm作為HPC發送器和Kubernetes作為容器編排工具,您可以利用Kubernetes的大量生態系統和服務,例如Helm Charts、CI/CD流水線、監控工具,以及相同的作業調度和管理介面提交HPC作業和容器化工作負載。實現將HPC作業和Kubernetes容器工作負載整合到同一個叢集中,更有效地利用硬體資源。