華為云原生Kubernetes之運行Volcano高性能作業(yè)的深度使用和實踐【與云原生的故事】
一、Volcano 簡介
① 什么是 Volcano ?
Volcano 是 CNCF 下首個也是唯一的基于 Kubernetes 的容器批量計算平臺,主要用于高性能計算場景,提供了機器學習、深度學習、生物信息學、基因組學及其他大數(shù)據(jù)應用所需要而 Kubernetes 當前缺失的一系列特性。
Volcano 提供高性能任務調(diào)度引擎、高性能異構芯片管理、高性能任務運行管理等通用計算能力,通過接入 AI、大數(shù)據(jù)、基因、渲染等諸多行業(yè)計算框架服務終端用戶。
Volcano 針對計算型應用提供了作業(yè)調(diào)度、作業(yè)管理、隊列管理等多項功能,主要特性包括:
豐富的計算框架支持:通過 CRD 提供了批量計算任務的通用 API,通過提供豐富的插件及作業(yè)生命周期高級管理,支持 TensorFlow,MPI,Spark 等計算框架容器化運行在 Kubernetes 上;
高級調(diào)度:面向批量計算、高性能計算場景提供豐富的高級調(diào)度能力,包括成組調(diào)度,優(yōu)先級搶占、裝箱、資源預留、任務拓撲關系等;
隊列管理:支持分隊列調(diào)度,提供隊列優(yōu)先級、多級隊列等復雜任務調(diào)度能力。
② Volcano 的特性
Volcano 支持各種調(diào)度策略,包括 Gang-scheduling、Fair-share scheduling、Queue scheduling、Preemption scheduling、Topology-based scheduling、Reclaims、Backfill、Resource Reservation 等,得益于可擴展性的架構設計,Volcano 支持用戶自定義 plugin 和 action 以支持更多調(diào)度算法;
Volcano 提供了增強型的 Job 管理能力以適配高性能計算場景,如多 pod 類型job、增強型的異常處理、可索引 Job;
Volcano 提供了基于多種架構的計算資源的混合調(diào)度能力:如 x86、ARM、鯤鵬、昇騰、GPU;
Volcano 已經(jīng)支持幾乎所有的主流計算框架:Spark、TensorFlow、PyTorch、Flink、Argo、MindSpore、PaddlePaddle、OpenMPI、Horovod、mxnet、Kubeflow、KubeGene、Cromwell 等。
③ Volcano 的系統(tǒng)架構
Volcano 與 Kubernetes 天然兼容,并為高性能計算而生,它遵循 Kubernetes 的設計理念和風格,如下所示:
Volcano 由 scheduler、controllermanager、admission 和 vcctl 組成:
Scheduler Volcano scheduler 通過一系列的 action 和 plugin 調(diào)度Job,并為它找到一個最適合的節(jié)點,與 Kubernetes default-scheduler 相比,Volcano 與眾不同的地方是它支持針對 Job 的多種調(diào)度算法;
Controllermanager Volcano controllermanager 管理 CRD 資源的生命周期,它主要由 Queue ControllerManager、 PodGroupControllerManager、 VCJob ControllerManager 構成;
Admission Volcano admission 負責對 CRD API 資源進行校驗;
Vcctl Volcano vcctl 是 Volcano 的命令行客戶端工具。
④ Volcano 的應用場景
⑤ Volcano 的安裝
Deployment Yaml 安裝方式支持 x86_64/arm64 兩種架構,在 kubernetes 集群上,執(zhí)行如下的 kubectl 指令:
For x86_64: kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml For arm64: kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development-arm64.yaml
也可以將 master 替換為指定的標簽或者分支(比如 release-1.5 分支表示最新的 v1.5.x 版本,v1.5.1 標簽表示 v1.5.1 版本)以安裝指定的 Volcano 版本。
如果沒有 kubernetes 集群,可以選擇在 github 下載 volcano 源代碼壓縮包,解壓后運行 volcano 的安裝腳本,這種安裝方式暫時只支持 x86_64 平臺:
# git clone https://github.com/volcano-sh/volcano.git # tar -xvf volcano-{Version}-linux-gnu.tar.gz # cd volcano-{Version}-linux-gnu # ./hack/local-up-volcano.sh
在集群中下載 Helm,可以根據(jù)以下指南安裝 Helm:[https://helm.sh/docs/intro/](安裝 Helm)(僅當使用 Helm 模式進行安裝時需要)。
如果想使用 Helm 部署 Volcano,請先確認已經(jīng)在集群中安裝了 Helm。
創(chuàng)建一個新的命名空間:
# kubectl create namespace volcano-system namespace/volcano-system created
使用 Helm 進行安裝:
# helm install helm/chart/volcano --namespace volcano-system --name volcano NAME: volcano LAST DEPLOYED: Tue Jul 23 20:07:29 2019 NAMESPACE: volcano-system STATUS: DEPLOYED RESOURCES: ==> v1/ClusterRole NAME AGE volcano-admission 1s volcano-controllers 1s volcano-scheduler 1s ==> v1/ClusterRoleBinding NAME AGE volcano-admission-role 1s volcano-controllers-role 1s volcano-scheduler-role 1s ==> v1/ConfigMap NAME DATA AGE volcano-scheduler-configmap 2 1s ==> v1/Deployment NAME READY UP-TO-DATE AVAILABLE AGE volcano-admission 0/1 1 0 1s volcano-controllers 0/1 1 0 1s volcano-scheduler 0/1 1 0 1s ==> v1/Job NAME COMPLETIONS DURATION AGE volcano-admission-init 0/1 1s 1s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE volcano-admission-b45b7b76-84jmw 0/1 ContainerCreating 0 1s volcano-admission-init-fw47j 0/1 ContainerCreating 0 1s volcano-controllers-5f66f8d76c-27584 0/1 ContainerCreating 0 1s volcano-scheduler-bb4467966-z642p 0/1 Pending 0 1s ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE volcano-admission-service ClusterIP 10.107.128.208
驗證 Volcano 組件的狀態(tài):
# kubectl get all -n volcano-system NAME READY STATUS RESTARTS AGE pod/volcano-admission-5bd5756f79-p89tx 1/1 Running 0 6m10s pod/volcano-admission-init-d4dns 0/1 Completed 0 6m10s pod/volcano-controllers-687948d9c8-bd28m 1/1 Running 0 6m10s pod/volcano-scheduler-94998fc64-9df5g 1/1 Running 0 6m10s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/volcano-admission-service ClusterIP 10.96.140.22
⑥ 使用 Volcano CRD 資源
創(chuàng)建一個名為 “test” 的自定義隊列:
# cat < 創(chuàng)建一個名為 “job-1” 的 Volcano Job: # cat < 檢查自定義 job 的狀態(tài): # kubectl get vcjob job-1 -oyaml apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: creationTimestamp: "2022-05-18T12:59:37Z" generation: 1 managedFields: - apiVersion: batch.volcano.sh/v1alpha1 fieldsType: FieldsV1 fieldsV1: f:spec: .: {} f:minAvailable: {} f:policies: {} f:queue: {} f:schedulerName: {} manager: kubectl operation: Update time: "2022-05-18T12:59:37Z" - apiVersion: batch.volcano.sh/v1alpha1 fieldsType: FieldsV1 fieldsV1: f:spec: f:tasks: {} f:status: .: {} f:minAvailable: {} f:running: {} f:state: .: {} f:lastTransitionTime: {} f:phase: {} manager: vc-controller-manager operation: Update time: "2022-05-18T12:59:45Z" name: job-1 namespace: default resourceVersion: "850500" selfLink: /apis/batch.volcano.sh/v1alpha1/namespaces/default/jobs/job-1 uid: 215409ec-7337-4abf-8bea-e6419defd688 spec: minAvailable: 1 policies: - action: RestartJob event: PodEvicted queue: test schedulerName: volcano tasks: - name: nginx policies: - action: CompleteJob event: TaskCompleted replicas: 1 template: spec: containers: - command: - sleep - 10m image: nginx:latest name: nginx resources: limits: cpu: 1 requests: cpu: 1 status: minAvailable: 1 running: 1 state: lastTransitionTime: "2022-05-18T12:59:45Z" phase: Running 檢查名為 ”job-1“ 的 PodGroup 的狀態(tài): # kubectl get podgroup job-1 -oyaml apiVersion: scheduling.volcano.sh/v1beta1 kind: PodGroup metadata: creationTimestamp: "2022-05-18T12:59:37Z" generation: 5 managedFields: - apiVersion: scheduling.volcano.sh/v1beta1 fieldsType: FieldsV1 fieldsV1: f:metadata: f:ownerReferences: .: {} k:{"uid":"215409ec-7337-4abf-8bea-e6419defd688"}: .: {} f:apiVersion: {} f:blockOwnerDeletion: {} f:controller: {} f:kind: {} f:name: {} f:uid: {} f:spec: .: {} f:minMember: {} f:minResources: .: {} f:cpu: {} f:queue: {} f:status: {} manager: vc-controller-manager operation: Update time: "2022-05-18T12:59:37Z" - apiVersion: scheduling.volcano.sh/v1beta1 fieldsType: FieldsV1 fieldsV1: f:status: f:conditions: {} f:phase: {} f:running: {} manager: vc-scheduler operation: Update time: "2022-05-18T12:59:45Z" name: job-1 namespace: default ownerReferences: - apiVersion: batch.volcano.sh/v1alpha1 blockOwnerDeletion: true controller: true kind: Job name: job-1 uid: 215409ec-7337-4abf-8bea-e6419defd688 resourceVersion: "850501" selfLink: /apis/scheduling.volcano.sh/v1beta1/namespaces/default/podgroups/job-1 uid: ea5b4f87-b750-440b-a41a-5c9944a7ae43 spec: minMember: 1 minResources: cpu: "1" queue: test status: conditions: - lastTransitionTime: "2022-05-18T12:59:38Z" message: '1/0 tasks in gang unschedulable: pod group is not ready, 1 minAvailable.' reason: NotEnoughResources status: "True" transitionID: 606145d1-660f-4e01-850d-ed556cebc098 type: Unschedulable - lastTransitionTime: "2022-05-18T12:59:45Z" reason: tasks in gang are ready to be scheduled status: "True" transitionID: 57e6ba9e-55cc-47ce-a37e-d8bddd99d54b type: Scheduled phase: Running running: 1 檢查隊列 “test” 的狀態(tài): # kubectl get queue test -oyaml apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: creationTimestamp: "2022-05-18T12:59:30Z" generation: 1 managedFields: - apiVersion: scheduling.volcano.sh/v1beta1 fieldsType: FieldsV1 fieldsV1: f:spec: .: {} f:capability: {} f:reclaimable: {} f:weight: {} manager: kubectl operation: Update time: "2022-05-18T12:59:30Z" - apiVersion: scheduling.volcano.sh/v1beta1 fieldsType: FieldsV1 fieldsV1: f:spec: f:capability: f:cpu: {} f:status: .: {} f:running: {} f:state: {} manager: vc-controller-manager operation: Update time: "2022-05-18T12:59:39Z" name: test resourceVersion: "850474" selfLink: /apis/scheduling.volcano.sh/v1beta1/queues/test uid: b9c9ee54-5ef8-4784-9bec-7a665acb1fde spec: capability: cpu: 2 reclaimable: false weight: 1 status: running: 1 state: Open 二、Kubernetes 運行作業(yè)的問題分析及解決方案 ① 報錯 cannot allocate memory 或者 no space left on device,修復 Kubernetes 內(nèi)存泄露問題 當 Kubernetes 集群運行日久以后,有的 Node 無法再新建 Pod,并且出現(xiàn)如下錯誤,當重啟服務器之后,才可以恢復正常使用,查看 Pod 狀態(tài)的時候會出現(xiàn)以下報錯: applying cgroup … caused: mkdir …no space left on device 或者在 describe pod 的時候出現(xiàn) cannot allocate memory 這時候 Kubernetes 集群可能就存在內(nèi)存泄露的問題,當創(chuàng)建的 Pod 越多的時候內(nèi)存會泄露的越多越快。具體查看是否存在內(nèi)存泄露: cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo 當出現(xiàn) cat: /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo: Input/output error 則說明不存在內(nèi)存泄露的情況 如果存在內(nèi)存泄露會出現(xiàn) slabinfo - version: 2.1 # name 可以考慮關閉 runc 和 kubelet 的 kmem,因為升級內(nèi)核的方案改動較大,此處不采用。 kmem 導致內(nèi)存泄露的原因:內(nèi)核對于每個 cgroup 子系統(tǒng)的的條目數(shù)是有限制的,限制的大小定義在 kernel/cgroup.c #L139,當正常在 cgroup 創(chuàng)建一個 group 的目錄時,條目數(shù)就加 1。 我們遇到的情況就是因為開啟 kmem accounting 功能,雖然 cgroup 的目錄刪除,但是條目沒有回收,這樣后面就無法創(chuàng)建 65535 個 cgroup。也就是說,在當前內(nèi)核版本下,開啟 kmem accounting 功能,會導致 memory cgroup 的條目泄漏無法回收。 需要重新編譯 runc: 配置 go 語言環(huán)境: wget https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz tar xf go1.12.9.linux-amd64.tar.gz -C /usr/local/ 寫入 bashrc vim ~/.bashrc export GOPATH="/data/Documents" export GOROOT="/usr/local/go" export PATH="$GOROOT/bin:$GOPATH/bin:$PATH" export GO111MODULE=off 驗證 source ~/.bashrc go env 下載 runc 源碼: mkdir -p /data/Documents/src/github.com/opencontainers/ cd /data/Documents/src/github.com/opencontainers/ git clone https://github.com/opencontainers/runc cd runc/ git checkout v1.0.0-rc9 # 切到 v1.0.0-rc9 tag 編譯: 安裝編譯組件 sudo yum install libseccomp-devel make BUILDTAGS='seccomp nokmem' 編譯完成之后會在當前目錄下看到一個runc的可執(zhí)行文件,等kubelet編譯完成之后會將其替換 編譯 kubelet: 下載 Kubernetes 源碼: mkdir -p /root/k8s/ cd /root/k8s/ git clone https://github.com/kubernetes/kubernetes cd kubernetes/ git checkout v1.15.3 制作編譯環(huán)境的鏡像 Dockerfile 如下: FROM centos:centos7.3.1611 ENV GOROOT /usr/local/go ENV GOPATH /usr/local/gopath ENV PATH /usr/local/go/bin:$PATH RUN yum install rpm-build which where rsync gcc gcc-c++ automake autoconf libtool make -y \ && curl -L https://studygolang.com/dl/golang/go1.12.9.linux-amd64.tar.gz | tar zxvf - -C /usr/local 在制作好的 go 環(huán)境鏡像中來進行編譯 kubelet: docker run -it --rm -v /root/k8s/kubernetes:/usr/local/gopath/src/k8s.io/kubernetes build-k8s:centos-7.3-go-1.12.9-k8s-1.15.3 bash cd /usr/local/gopath/src/k8s.io/kubernetes # 編譯 GO111MODULE=off KUBE_GIT_TREE_STATE=clean KUBE_GIT_VERSION=v1.15.3 make kubelet GOFLAGS="-tags=nokmem" 替換原有的 runc 和 kubelet: 將原有 runc 和 kubelet 備份: mv /usr/bin/kubelet /home/kubelet mv /usr/bin/docker-runc /home/docker-runc 停止 Docker 和 kubelet: systemctl stop docker systemctl stop kubelet 將編譯好的 runc 和 kubelet 進行替換: cp kubelet /usr/bin/kubelet cp kubelet /usr/local/bin/kubelet cp runc /usr/bin/docker-runc 檢查 kmem 是否關閉前需要將此節(jié)點的 Pod 殺掉重啟或者重啟服務器,當結果為 0 時成功: cat /sys/fs/cgroup/memory/kubepods/burstable/memory.kmem.usage_in_bytes 是否還存在內(nèi)存泄露的情況: cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo ② Kubernetes 證書過期問題的解決 出現(xiàn) Kubernetes API 無法調(diào)取的現(xiàn)象,使用 kubectl 命令獲取資源均返回如下報錯: Unable to connect to the server: x509: certificate has expired or is not yet valid 可以猜測 Kubernetes 集群的證書過期,使用命令排查證書的過期時間: kubeadm alpha certs check-expiration 由于使用 kubeadm 部署的 Kubernetes 集群,所以更新起證書也是比較方便的,默認的證書時間有效期是一年,集群的 Kubernetes 版本是 1.15.3版本是可以使用以下命令來更新證書的,但是一年之后還是會到期,這樣就很麻煩,所以需要了解一下 Kubernetes 的證書,然后來生成一個時間很長的證書,這樣就可以不用去總更新證書: kubeadm alpha certs renew all --config=kubeadm.yaml systemctl restart kubelet kubeadm init phase kubeconfig all --config kubeadm.yaml 然后將生成的配置文件替換,重啟 kube-apiserver、kube-controller、kube-scheduler、etcd 這 4 個容器即可 另外 kubeadm 會在控制面板升級的時候自動更新所有證書,所以使用 kubeadm 搭建得集群最佳的做法是經(jīng)常升級集群,這樣可以確保集群保持最新狀態(tài)并保持合理的安全性。但是對于實際的生產(chǎn)環(huán)境我們可能并不會去頻繁得升級集群,所以這個時候就需要去手動更新證書: 首先在/etc/kubernetes/manifests/kube-controller-manager.yaml文件加入配置 spec: containers: - command: - kube-controller-manager # 設置證書有效期為10年 - --experimental-cluster-signing-duration=87600h - --client-ca-file=/etc/kubernetes/pki/ca.crt 修改完成后 kube-controller-manager 會自動重啟生效,然后需要使用下面的命令為 Kubernetes 證書 API 創(chuàng)建一個證書簽名請求,如果設置例如 cert-manager 等外部簽名者,則會自動批準證書簽名請求(CSRs)。否者,必須使用 kubectl certificate 命令手動批準證書,以下 kubeadm 命令輸出要批準的證書名稱,然后等待批準發(fā)生。如下所示,通過調(diào)用 Kubernetes 的 API 來實現(xiàn)更新一個 10 年的證書: kubeadm alpha certs renew all --use-api --config kubeadm.yaml & 需要將全部 pending 的證書全部批準,還不能直接重啟控制面板的幾個組件,這是因為使用 kubeadm 安裝的集群對應的 etcd 默認是使用的 /etc/kubernetes/pki/etcd/ca.crt 這個證書進行前面的,而上面用命令 kubectl certificate approve 批準過后的證書是使用的默認的 /etc/kubernetes/pki/ca.crt 證書進行簽發(fā)的,因此需要替換 etcd 中的 CA 機構證書: # 先拷貝靜態(tài)Pod資源清單 cp -r /etc/kubernetes/manifests/ /etc/kubernetes/manifests.bak vi /etc/kubernetes/manifests/etcd.yaml ...... spec: containers: - command: - etcd # 修改為CA文件 - --peer-trusted-ca-file=/etc/kubernetes/pki/ca.crt - --trusted-ca-file=/etc/kubernetes/pki/ca.crt ...... volumeMounts: - mountPath: /var/lib/etcd name: etcd-data - mountPath: /etc/kubernetes/pki # 更改證書目錄 name: etcd-certs volumes: - hostPath: path: /etc/kubernetes/pki # 將 pki 目錄掛載到etcd中去 type: DirectoryOrCreate name: etcd-certs - hostPath: path: /var/lib/etcd type: DirectoryOrCreate name: etcd-data ...... 由于 kube-apiserver 要連接 etcd 集群,因此也需要重新修改對應的 etcd ca 文件: vi /etc/kubernetes/manifests/kube-apiserver.yaml ...... spec: containers: - command: - kube-apiserver # 將etcd ca文件修改為默認的ca.crt文件 - --etcd-cafile=/etc/kubernetes/pki/ca.crt ...... 除此之外還需要替換 requestheader-client-ca-file 文件,默認是 /etc/kubernetes/pki/front-proxy-ca.crt 文件,現(xiàn)在也需要替換成默認的 CA 文件,否則使用聚合 API,比如安裝 metrics-server 后執(zhí)行 kubectl top 命令就會報錯: cp /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/front-proxy-ca.crt cp /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/front-proxy-ca.key 這樣就得到了一個 10 年證書的 Kubernetes 集群,還可以通過重新編譯 kubeadm 來實現(xiàn)一個 10 年證書。 三、Volcano 容器在氣象行業(yè) HPC 高性能計算場景的應用 ① 什么是 HPC ? HPC 是 High Performance Computing(高性能計算)的縮寫,平時提到的 HPC,一般指代高性能計算機群(HPCC),它將大量的計算機軟件/硬件整合起來,將大的計算作業(yè)分解成一個個小部分,通過并行計算的方式加以解決。HPC 高性能計算在 CAE 仿真、動漫渲染、物理化學、石油勘探、生命科學、氣象環(huán)境等領域有廣泛的應用。 一般來說,高性能計算集群(HPCC)包含如下部分: PBS:Protable Batch System,資源管理器,負責管理集群中所有節(jié)點的資源,除了 PBS 意外,常用的資源管理系統(tǒng)還有 Slurm,LSF 等; Maui:第三方任務調(diào)度器,支持資源預留,支持各種復雜的優(yōu)先級策略,支持搶占機制等,資源管理器中內(nèi)置了默認的任務調(diào)取器,但功能往往比較簡單; OpenMPI:上層通信環(huán)境,兼顧通信庫,編譯,分布式啟動任務的功能。 PBS 和 Maui 對于用戶來說是完全透明的,用戶只需要按照 PBS 提供的方式提交作業(yè)即可,不需要了解內(nèi)部細節(jié),而 OpenMPI 則需要用戶進行相關了解,來編寫能夠并行計算的應用。 以 mpirun -np 4 ./mpi_hello_world 為例介紹 mpi 作業(yè)是如何運行的: 說明: 調(diào)用 openmpi 或者其他 mpi 的庫來編寫源代碼,示例就是輸出 hello world 字符串; 使用支持 MPI 的編譯器來編譯出可執(zhí)行程序 mpi_hello_world; 將 mpi_hello_world 分發(fā)到各個節(jié)點,也可以通過共享文件系統(tǒng)來實現(xiàn)對 mpi_hello_world 的訪問; 運行 mpirun 來并行執(zhí)行 mpi_hello_world。 ② 什么是 WRF ? WRF 是 Weather Research and Forecasting Model(天氣研究和預報模型)的簡稱,是一種比較常見的 HPC 應用,WRF 是一種中尺度數(shù)值天氣預報系統(tǒng),設計用于大氣研究和業(yè)務預報應用,可以根據(jù)實際的大氣條件或理想化的條件進行模擬。 由于 WRF 包含多個模塊,因此處理流程可能不盡相同,這里僅以 WPS 和 WRF 這兩個模塊為例介紹一下完整的 WRF 流程: 外部數(shù)據(jù)源:包含靜態(tài)地理數(shù)據(jù),網(wǎng)絡數(shù)據(jù)等,靜態(tài)地理數(shù)據(jù)可以理解為某區(qū)域內(nèi)的地理信息,例如山川,河流,湖泊,森林等等。網(wǎng)絡數(shù)據(jù)是某區(qū)域內(nèi)的氣象環(huán)境數(shù)據(jù),例如氣溫,風速風向,空氣濕度,降雨量等。 前處理系統(tǒng) WRF Pre-processing System:前處理系統(tǒng)用于載入地理和氣象數(shù)據(jù),對氣象數(shù)據(jù)進行插值,為 WRF 提供輸入數(shù)據(jù),該部分包含 3 個程序: geogrid.exe:定義模型投影、區(qū)域范圍,嵌套關系,對地表參數(shù)進行插值,處理地形資料和網(wǎng)格數(shù)據(jù); ungrib.exe:從 grib 數(shù)據(jù)中提取所需要的氣象參數(shù); metgrid.exe:將氣象參數(shù)插值到模擬區(qū)域。 核心模擬系統(tǒng)(WRF):核心模擬系統(tǒng)對前處理系統(tǒng)生成的氣象信息進行模擬和預報,是 WRF 的核心模塊,該部分包含 2 個程序: real.exe:初始化實際氣象數(shù)據(jù); wrf.exe:模擬及預報結果; real.exe 和 wrf.exe 可以通過 mpi 并行運算來提升計算速度,如下所示,wrfinput_d0X 和 wrfbdy_d0X 為 real.exe 的運算結果,wrf.exe 以該結果為輸入進行模擬演算,生成最終的氣象模擬結果 wrfout_dxx_yyyy-mm-dd_hh:mm:ss,并由后處理系統(tǒng)進行驗證展示: 后處理系統(tǒng)用來驗證和顯示核心模擬系統(tǒng)的計算結果,主要由各種第三方圖像和驗證工具組成。如下所示展示 Conus 2.5km 算例中各個地區(qū)相對濕度的模擬預報結果,Conus 2.5km 是指美國本土氣象數(shù)據(jù),分辨率為 2.5km(將整個區(qū)域分成一個個 2.5km2.5km2.5km 的方格,每個方格中的氣象信息被認為是完全一致的): ③ HPC Volcano 如下所示,一個 HPCC 包括資源管理器,調(diào)度器和 mpi 并行計算庫三部分,其中資源管理器由 Kubernetes 負責,調(diào)度器由 Volcano 負責: 在 Kubernetes+Volcano 環(huán)境中運行 HPC 應用,本質(zhì)上就是在容器中運行 HPC 作業(yè),示意圖如下: 將運行的容器分為 Master 容器和 Worker 容器兩種,Master 容器負責啟動 mpirun/mpiexec 命令,Worker 容器負責運行真正的計算作業(yè)。因此 Volcano 為了支持 MPI 作業(yè)運行,添加了如下功能: Volcano job 支持定義多個 pod 模板,能夠同時定義 master pod 和 worker pod; 支持 Gang scheduling,保證作業(yè)中所有的 pod 能夠同時啟動; Master/Worker pod 內(nèi)部主機 IP 映射; Master/Workerpod 之間 ssh 免密登錄; 作業(yè)生命周期管理。 Volcano mpi 作業(yè)配置 mpi_sample.yaml: apiVersion: batch.Volcano.sh/v1alpha1 kind: Job metadata: name: mpi-job labels: # 根據(jù)業(yè)務需要設置作業(yè)類型 "Volcano.sh/job-type": "MPI" spec: # 設置最小需要的服務 (小于總replicas數(shù)) # 這里等于mpimaster和mpiworker的總數(shù) minAvailable: 3 # 指定調(diào)度器為Volcano schedulerName: Volcano plugins: # 提供 ssh 免密認證 ssh: [] # 提供運行作業(yè)所需要的網(wǎng)絡信息,hosts文件,headless service等 svc: [] # 如果有pod被 殺死,重啟整個作業(yè) policies: - event: PodEvicted action: RestartJob tasks: - replicas: 1 name: mpimaster # 當 mpiexec 結束,認為整個mpi作業(yè)結束 policies: - event: TaskCompleted action: CompleteJob template: spec: # Volcano的信息會統(tǒng)一放到 /etc/Volcano 目錄下 containers: # master容器中 # 1. 啟動sshd服務 # 2. 通過/etc/Volcano/mpiworker.host獲取mpiworker容器列表 # 3. 運行mpirun/mpiexec - command: - /bin/sh - -c - | MPI_HOST=`cat /etc/Volcano/mpiworker.host | tr "\n" ","`; mkdir -p /var/run/sshd; /usr/sbin/sshd; mpiexec --allow-run-as-root --host ${MPI_HOST} -np 2 mpi_hello_world; image: Volcanosh/example-mpi:0.0.1 imagePullPolicy: IfNotPresent name: mpimaster ports: - containerPort: 22 name: mpijob-port workingDir: /home resources: requests: cpu: "100m" memory: "1024Mi" limits: cpu: "100m" memory: "1024Mi" restartPolicy: OnFailure imagePullSecrets: - name: default-secret - replicas: 2 name: mpiworker template: spec: containers: # worker容器中只需要啟動sshd服務 - command: - /bin/sh - -c - | mkdir -p /var/run/sshd; /usr/sbin/sshd -D; image: Volcanosh/example-mpi:0.0.1 imagePullPolicy: IfNotPresent name: mpiworker ports: - containerPort: 22 name: mpijob-port workingDir: /home resources: requests: cpu: "100m" memory: "2048Mi" limits: cpu: "100m" memory: "2048Mi" restartPolicy: OnFailure imagePullSecrets: - name: default-secret 提交 mpi Volcano job: 作業(yè)執(zhí)行完畢: 查看 master pod 的結果: 通過上述執(zhí)行結果可以看出,在作業(yè)執(zhí)行結束后,Volcano 只清理 worker pod,保留 master pod,這樣用戶 kubectl 命令獲取執(zhí)行結果。 此外,由于網(wǎng)絡構建可能會出現(xiàn)延遲,在作業(yè)運行開始時,master pod 會出現(xiàn)連接 worker pod 失敗的情況。對于這種情況,Volcano 會自動重啟 master pod,保證作業(yè)能夠正確運行。 通過以上示例,可以看出 Volcano 想要運行 WRF 作業(yè)的話,理論上需要將其中的 mpi_hello_world 替換為 real.exe/wrf.exe,此外,用戶還需要進行如下準備: 自建 docker images,包含完整的 WRF 運行環(huán)境; 將計算所需要的數(shù)據(jù)(原生數(shù)據(jù)或者中間結果數(shù)據(jù))掛載到相應的容器中。 這樣就能在 Kubernetes+Volcano 上運行氣象模擬作業(yè)。 四、附錄 本文正在參與【與云原生的故事】有獎征文火熱進行中:https://bbs.huaweicloud.com/blogs/345260 。 Kubernetes Volcano 云原生 云端實踐
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。