使用 GPU 工作負載搭配 Azure Red Hat OpenShift

本文說明如何搭配 Azure Red Hat OpenShift 使用 NVIDIA GPU 工作負載。

先決條件

  • OpenShift CLI
  • jq、moreutils 和 gettext 套件
  • Azure Red Hat OpenShift 4.10

如果您需要安裝叢集,請參閱 教學課程:建立 Azure Red Hat OpenShift 4 叢集。 叢集必須是 4.10.x 版或更新版本。

備註

從 4.10 開始,不再需要設定權利即可使用 NVIDIA Operator。 這已大幅簡化 GPU 工作負載的叢集設定。

Linux:

sudo dnf install jq moreutils gettext

macOS

brew install jq moreutils gettext

要求 GPU 配額

依預設,Azure 中的所有 GPU 配額都是 0。 您必須登入 Azure 入口網站並要求 GPU 配額。 由於 GPU 工作者的競爭,您可能必須在實際可以保留 GPU 的區域中佈建叢集。

支援下列 GPU 工作者:

  • NC4作為 T4 v3
  • NC6s v3
  • NC8as T4 v3
  • NC12s v3
  • NC16作為 T4 v3
  • NC24s v3
  • NC24rs v3
  • NC64 T4 v3 型號

其他 MachineSet 也支援下列執行個體:

  • Standard_ND96asr_v4
  • NC24ads_A100_v4
  • NC48ads_A100_v4
  • NC96ads_A100_v4
  • ND96amsr_A100_v4

備註

要求配額時,請記住 Azure 是每個核心。 若要要求單一 NC4as T4 v3 節點,您將必須一一組 4 個的形式要求配額。 如果您想要要求 NC16as T4 v3,您將必須要求配額 16 個。

  1. 登入 Azure 入口網站。

  2. 在搜尋方塊中輸入配額,然後選取 [計算]。

  3. 在搜尋方塊中,輸入 NCAsv3_T4,勾選叢集所在的區域方塊,然後選取 [申請加大配額]。

  4. 設定配額。

    螢幕擷取畫面:Azure 入口網站上的配額頁面。

登入叢集

使用具有叢集管理員權限的使用者帳戶登入 OpenShift。 下列範例使用名為 kubadmin 的帳戶:

oc login <apiserver> -u kubeadmin -p <kubeadminpass>

提取祕密 (條件式)

更新您的提取祕密,以確定您可以安裝操作員並連線到 cloud.redhat.com。

備註

如果您已經重新建立已啟用 cloud.redhat.com 的完整提取祕密,請略過此步驟。

  1. 登入 cloud.redhat.com。

  2. 瀏覽至 https://cloud.redhat.com/openshift/install/azure/aro-provisioned。

  3. 選取 [下載提取祕密],並將提取祕密儲存為 pull-secret.txt。

    這很重要

    本節中的其餘步驟必須在與 pull-secret.txt 相同的工作目錄中執行。

  4. 匯出現有的提取祕密。

    oc get secret pull-secret -n openshift-config -o json | jq -r '.data.".dockerconfigjson"' | base64 --decode > export-pull.json
    
  5. 將下載的提取祕密與系統提取祕密合併,以新增 cloud.redhat.com。

    jq -s '.[0] * .[1]' export-pull.json pull-secret.txt | tr -d "\n\r" > new-pull-secret.json
    
  6. 上傳新祕密檔案。

    oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=new-pull-secret.json
    

    您可能需要等候大約 1 小時,所有項目才能與 cloud.redhat.com 同步。

  7. 刪除祕密。

    rm pull-secret.txt export-pull.json new-pull-secret.json
    

GPU 機器集

使用 Kubernetes MachineSet 來建立機器集。 下列程序說明如何匯出叢集中的第一部機器,並使用該機器作為範本來建置單一 GPU 機器。

  1. 檢視現有的機器集。

    為方便設定起見,此範例會使用第一個機器集做為複製品來建立新的 GPU 機器集。

    MACHINESET=$(oc get machineset -n openshift-machine-api -o=jsonpath='{.items[0]}' | jq -r '[.metadata.name] | @tsv')
    
  2. 儲存範例機器集的複本。

    oc get machineset -n openshift-machine-api $MACHINESET -o json > gpu_machineset.json
    
  3. 將 .metadata.name 欄位變更為新的唯一名稱。

    jq '.metadata.name = "nvidia-worker-<region><az>"' gpu_machineset.json| sponge gpu_machineset.json
    
  4. 確保 spec.replicas 符合機器集所需的複本計數。

    jq '.spec.replicas = 1' gpu_machineset.json| sponge gpu_machineset.json
    
  5. 將 .spec.selector.matchLabels.machine.openshift.io/cluster-api-machineset 欄位變更以符合 .metadata.name 欄位。

    jq '.spec.selector.matchLabels."machine.openshift.io/cluster-api-machineset" = "nvidia-worker-<region><az>"' gpu_machineset.json| sponge gpu_machineset.json
    
  6. 將 .spec.template.metadata.labels.machine.openshift.io/cluster-api-machineset 變更以符合 .metadata.name 欄位。

    jq '.spec.template.metadata.labels."machine.openshift.io/cluster-api-machineset" = "nvidia-worker-<region><az>"' gpu_machineset.json| sponge gpu_machineset.json
    
  7. 將 spec.template.spec.providerSpec.value.vmSize 變更以符合來自 Azure 所需的 GPU 執行個體類型。

    此範例中使用的機器為 Standard_NC4as_T4_v3。

    jq '.spec.template.spec.providerSpec.value.vmSize = "Standard_NC4as_T4_v3"' gpu_machineset.json | sponge gpu_machineset.json
    
  8. 將 spec.template.spec.providerSpec.value.zone 變更以符合來自 Azure 所需的區域。

    jq '.spec.template.spec.providerSpec.value.zone = "1"' gpu_machineset.json | sponge gpu_machineset.json
    
  9. 刪除 yaml 檔案的 .status 區段。

    jq 'del(.status)' gpu_machineset.json | sponge gpu_machineset.json
    
  10. 驗證 yaml 檔案中的其他資料。

確定已設定正確的 SKU

根據機器集所使用的映像,必須據以設定 和 image.sku 的值image.version。 這是為了確保 Hyper-V 的層代 1 或 2 虛擬機是否使用。 如需詳細資訊,請參閱 此處 。

範例:

如果使用 Standard_NC4as_T4_v3,則支援這兩個版本。 如功能支援中所述。 在此情況下,不需要變更。

Standard_NC24ads_A100_v4如果使用 ,則僅支援第 2 代 VM。 在此情況下,image.sku值必須遵循對應至叢集原始 v2的對等image.sku映像版本。 在這裡範例中,值會是 v410-v2。

您可以使用下列命令找到此項目:

az vm image list --architecture x64 -o table --all --offer aro4 --publisher azureopenshift
Filtered output:

SKU      VERSION
-------  ---------------
v410-v2  410.84.20220125
aro_410  410.84.20220125

如果叢集是以基底 SKU 映射 aro_410建立,而且機器集中會保留相同的值,則會失敗並出現下列錯誤:

failure sending request for machine myworkernode: cannot create vm: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="BadRequest" Message="The selected VM size 'Standard_NC24ads_A100_v4' cannot boot Hypervisor Generation '1'.

建立 GPU 機器集

使用下列步驟來建立新的 GPU 機器。 佈建新的 GPU 機器可能需要 10-15 分鐘的時間。 如果此步驟失敗,請登入 Azure 入口網站,並確保沒有可用性問題。 若要這樣做,請移至虛擬機器,並搜尋您先前建立的背景工作角色名稱,以查看 VM 的狀態。

  1. 建立 GPU 機器集。

    oc create -f gpu_machineset.json
    

    此命令將需要數分鐘才能完成。

  2. 驗證 GPU 機器集。

    機器應該為部署中。 您可以使用下列命令來檢視機器集的狀態:

    oc get machineset -n openshift-machine-api
    oc get machine -n openshift-machine-api
    

    一旦機器佈建 (可能需要 5-15 分鐘的時間),機器就會顯示為節點清單中的節點:

    oc get nodes
    

    您應該會看到具有先前建立名稱 nvidia-worker-southcentralus1 的節點。

安裝 NVIDIA GPU作員

本節說明如何建立 nvidia-gpu-operator 命名空間、設定作員群組,以及安裝 NVIDIA GPU 運算符。

  1. 建立 NVIDIA 命名空間。

    cat <<EOF | oc apply -f -
    apiVersion: v1
    kind: Namespace
    metadata:
      name: nvidia-gpu-operator
    EOF
    
  2. 建立操作員群組。

    cat <<EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: nvidia-gpu-operator-group
      namespace: nvidia-gpu-operator
    spec:
     targetNamespaces:
     - nvidia-gpu-operator
    EOF
    
  3. 使用下列命令取得最新的 NVIDIA 通道:

    CHANNEL=$(oc get packagemanifest gpu-operator-certified -n openshift-marketplace -o jsonpath='{.status.defaultChannel}')
    

備註

如果您的叢集在建立時未提供提取秘密,叢集將不會包含來自 Red Hat 或來自認證合作夥伴的範例或操作員。 這會導致下列錯誤訊息:

伺服器錯誤 (NotFound):找不到 packagemanifests.packages.operators.coreos.com "gpu-operator-certified"。

若要在 Azure Red Hat OpenShift 叢集上新增您的 Red Hat 提取秘密,請遵循此指南。

  1. 使用下列命令取得最新的 NVIDIA 套件:

    PACKAGE=$(oc get packagemanifests/gpu-operator-certified -n openshift-marketplace -ojson | jq -r '.status.channels[] | select(.name == "'$CHANNEL'") | .currentCSV')
    
  2. 建立訂用帳戶。

    envsubst  <<EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: gpu-operator-certified
      namespace: nvidia-gpu-operator
    spec:
      channel: "$CHANNEL"
      installPlanApproval: Automatic
      name: gpu-operator-certified
      source: certified-operators
      sourceNamespace: openshift-marketplace
      startingCSV: "$PACKAGE"
    EOF
    
  3. 等候操作員完成安裝。

    驗證操作員已完成安裝之前,請勿繼續進行。 此外,確保您的 GPU 背景工作角色在線上。

    螢幕擷取畫面:命名空間上的已安裝操作員。

安裝節點功能探索操作員

節點功能探索操作員將探索節點上的 GPU,並適當地為節點加上標籤,讓您可以針對工作負載將其設為目標。

此範例會將 NFD 操作員安裝到 openshift-ndf 命名空間,並建立 "subscription",其為 NFD 的設定。

安裝節點功能探索操作員的官方文件。

  1. 設定 Namespace。

    cat <<EOF | oc apply -f -
    apiVersion: v1
    kind: Namespace
    metadata:
      name: openshift-nfd
    EOF
    
  2. 建立 OperatorGroup。

    cat <<EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      generateName: openshift-nfd-
      name: openshift-nfd
      namespace: openshift-nfd
    EOF
    
  3. 建立 Subscription。

    cat <<EOF | oc apply -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: nfd
      namespace: openshift-nfd
    spec:
      channel: "stable"
      installPlanApproval: Automatic
      name: nfd
      source: redhat-operators
      sourceNamespace: openshift-marketplace
    EOF
    
  4. 等候節點功能探索完成安裝。

    您可以登入 OpenShift 主控台來檢視操作員,或只是等候幾分鐘。 無法等候操作員安裝會導致下一個步驟中發生錯誤。

  5. 建立 NFD 執行個體。

    cat <<EOF | oc apply -f -
    kind: NodeFeatureDiscovery
    apiVersion: nfd.openshift.io/v1
    metadata:
      name: nfd-instance
      namespace: openshift-nfd
    spec:
      customConfig:
        configData: |
          #    - name: "more.kernel.features"
          #      matchOn:
          #      - loadedKMod: ["example_kmod3"]
          #    - name: "more.features.by.nodename"
          #      value: customValue
          #      matchOn:
          #      - nodename: ["special-.*-node-.*"]
      operand:
        image: >-
          registry.redhat.io/openshift4/ose-node-feature-discovery@sha256:07658ef3df4b264b02396e67af813a52ba416b47ab6e1d2d08025a350ccd2b7b
        servicePort: 12000
      workerConfig:
        configData: |
          core:
          #  labelWhiteList:
          #  noPublish: false
            sleepInterval: 60s
          #  sources: [all]
          #  klog:
          #    addDirHeader: false
          #    alsologtostderr: false
          #    logBacktraceAt:
          #    logtostderr: true
          #    skipHeaders: false
          #    stderrthreshold: 2
          #    v: 0
          #    vmodule:
          ##   NOTE: the following options are not dynamically run-time
          ##          configurable and require a nfd-worker restart to take effect
          ##          after being changed
          #    logDir:
          #    logFile:
          #    logFileMaxSize: 1800
          #    skipLogHeaders: false
          sources:
          #  cpu:
          #    cpuid:
          ##     NOTE: attributeWhitelist has priority over attributeBlacklist
          #      attributeBlacklist:
          #        - "BMI1"
          #        - "BMI2"
          #        - "CLMUL"
          #        - "CMOV"
          #        - "CX16"
          #        - "ERMS"
          #        - "F16C"
          #        - "HTT"
          #        - "LZCNT"
          #        - "MMX"
          #        - "MMXEXT"
          #        - "NX"
          #        - "POPCNT"
          #        - "RDRAND"
          #        - "RDSEED"
          #        - "RDTSCP"
          #        - "SGX"
          #        - "SSE"
          #        - "SSE2"
          #        - "SSE3"
          #        - "SSE4.1"
          #        - "SSE4.2"
          #        - "SSSE3"
          #      attributeWhitelist:
          #  kernel:
          #    kconfigFile: "/path/to/kconfig"
          #    configOpts:
          #      - "NO_HZ"
          #      - "X86"
          #      - "DMI"
            pci:
              deviceClassWhitelist:
                - "0200"
                - "03"
                - "12"
              deviceLabelFields:
          #      - "class"
                - "vendor"
          #      - "device"
          #      - "subsystem_vendor"
          #      - "subsystem_device"
          #  usb:
          #    deviceClassWhitelist:
          #      - "0e"
          #      - "ef"
          #      - "fe"
          #      - "ff"
          #    deviceLabelFields:
          #      - "class"
          #      - "vendor"
          #      - "device"
          #  custom:
          #    - name: "my.kernel.feature"
          #      matchOn:
          #        - loadedKMod: ["example_kmod1", "example_kmod2"]
          #    - name: "my.pci.feature"
          #      matchOn:
          #        - pciId:
          #            class: ["0200"]
          #            vendor: ["15b3"]
          #            device: ["1014", "1017"]
          #        - pciId :
          #            vendor: ["8086"]
          #            device: ["1000", "1100"]
          #    - name: "my.usb.feature"
          #      matchOn:
          #        - usbId:
          #          class: ["ff"]
          #          vendor: ["03e7"]
          #          device: ["2485"]
          #        - usbId:
          #          class: ["fe"]
          #          vendor: ["1a6e"]
          #          device: ["089a"]
          #    - name: "my.combined.feature"
          #      matchOn:
          #        - pciId:
          #            vendor: ["15b3"]
          #            device: ["1014", "1017"]
          #          loadedKMod : ["vendor_kmod1", "vendor_kmod2"]
    EOF
    
  6. 驗證 NFD 已就緒。

    此操作員的狀態應該會顯示為 [可用]。

    螢幕擷取畫面:節點功能探索操作員。

套用 NVIDIA 叢集設定

本節說明如何套用 NVIDIA 叢集設定。 如果您有自己的私人存放庫或特定設定,請閱讀 NVIDIA 檔 ,以自定義此檔案。 此過程可能需要幾分鐘才能完成。

  1. 套用叢集設定。

    cat <<EOF | oc apply -f -
    apiVersion: nvidia.com/v1
    kind: ClusterPolicy
    metadata:
      name: gpu-cluster-policy
    spec:
      migManager:
        enabled: true
      operator:
        defaultRuntime: crio
        initContainer: {}
        runtimeClass: nvidia
        deployGFD: true
      dcgm:
        enabled: true
      gfd: {}
      dcgmExporter:
        config:
          name: ''
      driver:
        licensingConfig:
          nlsEnabled: false
          configMapName: ''
        certConfig:
          name: ''
        kernelModuleConfig:
          name: ''
        repoConfig:
          configMapName: ''
        virtualTopology:
          config: ''
        enabled: true
        use_ocp_driver_toolkit: true
      devicePlugin: {}
      mig:
        strategy: single
      validator:
        plugin:
          env:
            - name: WITH_WORKLOAD
              value: 'true'
      nodeStatusExporter:
        enabled: true
      daemonsets: {}
      toolkit:
        enabled: true
    EOF
    
  2. 驗證叢集原則。

    登入 OpenShift 主控台並瀏覽至操作員。 確保您位於 nvidia-gpu-operator 命名空間中。 系統應顯示:State: Ready once everything is complete。

    螢幕擷取畫面:OpenShift 主控台上的現有叢集原則。

驗證 GPU

NVIDIA作員和 NFD 可能需要一些時間才能完全安裝和自我識別機器。 執行下列命令來驗證所有項目如預期般執行:

  1. 驗證 NFD 可以看到 GPU。

    oc describe node | egrep 'Roles|pci-10de' | grep -v master
    

    輸出應該如下所示:

    Roles:              worker
                    feature.node.kubernetes.io/pci-10de.present=true
    
  2. 驗證節點標籤。

    您可以登入 OpenShift 主控台 -> Compute -> Nodes -> nvidia-worker-southcentralus1- 來查看節點標籤。 您應該會看到多個 NVIDIA GPU 標籤和上述 pci-10de 裝置。

    螢幕擷取畫面:OpenShift 主控台上的 GPU 標籤。

  3. NVIDIA SMI 工具驗證。

    oc project nvidia-gpu-operator
    for i in $(oc get pod -lopenshift.driver-toolkit=true --no-headers |awk '{print $1}'); do echo $i; oc exec -it $i -- nvidia-smi ; echo -e '\n' ;  done
    

    您應該會看到輸出,其顯示主機上可用的 GPU,例如此範例螢幕擷取畫面。 (視 GPU 背景工作角色類型而有所不同)

    螢幕擷取畫面:顯示可用的 GPU 輸出。

  4. 建立 Pod 以執行 GPU 工作負載

    oc project nvidia-gpu-operator
    cat <<EOF | oc apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: cuda-vector-add
    spec:
      restartPolicy: OnFailure
      containers:
        - name: cuda-vector-add
          image: "quay.io/giantswarm/nvidia-gpu-demo:latest"
          resources:
            limits:
              nvidia.com/gpu: 1
          nodeSelector:
            nvidia.com/gpu.present: true
    EOF
    
  5. 檢視記錄。

    oc logs cuda-vector-add --tail=-1
    

備註

如果您收到錯誤 Error from server (BadRequest): container "cuda-vector-add" in pod "cuda-vector-add" is waiting to start: ContainerCreating,請嘗試執行 oc delete pod cuda-vector-add,然後重新執行上述 create 陳述式。

輸出應該類似以下 (視 GPU 而定):

[Vector addition of 5000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

如果成功,則可以刪除 Pod:

oc delete pod cuda-vector-add