對于基礎設施或站點可靠性工程( SRE )團隊來說,監控多個 GPU 對于管理大型 GPU 集群以實現 AI 或 HPC 工作負載至關重要。 GPU 指標允許團隊了解工作負載行為,從而優化資源分配和利用率,診斷異常,并提高數據中心的整體效率。除了基礎設施團隊之外,無論您是從事 GPU – 加速 ML 工作流的研究人員,還是喜歡了解 GPU 利用率和容量規劃飽和的數據中心設計師,您應該都對指標感興趣。

這些趨勢變得更為重要,因為 AI / ML 工作負載通過使用 Kubernetes 之類的容器管理平臺進行容器化和擴展。在這篇文章中,我們將概述 NVIDIA 數據中心 GPU 經理( DCGM ),以及如何將其集成到諸如 Prometheus 和 Grafana 這樣的開源工具中,從而為 Kubernetes 構建一個 GPU 監控解決方案。
NVIDIA DCGM 公司
NVIDIA DCGM 公司 是一組用于在基于 Linux 的大規模集群環境中管理和監視 NVIDIA GPUs 的工具。它是一個低開銷的工具,可以執行各種功能,包括主動健康監視、診斷、系統驗證、策略、電源和時鐘管理、組配置和記帳。有關詳細信息,請參閱 DCGM 用戶指南 。
DCGM 包括用于收集 GPU 遙測的 API。特別感興趣的是 GPU 利用率指標(用于監視張量核心、 FP64 單元等)、內存指標和互連流量指標。 DCGM 為各種語言(如 C 和 Python )提供了綁定,這些都包含在安裝程序包中。為了與 Go 作為編程語言流行的容器生態系統集成,有基于 DCGM API 的 Go 綁定 。存儲庫包括示例和 restapi ,以演示如何使用 Go API 監視 GPUs 。去看看 NVIDIA/gpu-monitoring-tools repo !
導出
監控堆棧通常由一個收集器、一個存儲度量的時間序列數據庫和一個可視化層組成。一個流行的開源堆棧是 Prometheus ,與 Grafana 一起作為可視化工具來創建豐富的儀表板。普羅米修斯還包括 Alertmanager 來創建和管理警報。 Prometheus 與 kube-state-metrics 和 node_exporter 一起部署,以公開 kubernetesapi 對象的集群級指標和節點級指標,如 CPU 利用率。圖 1 顯示了普羅米修斯的一個架構示例。

在前面描述的 Go API 的基礎上,可以使用 DCGM 向 Prometheus 公開 GPU 度量。為此,我們建立了一個名為 dcgm-exporter
的項目。
dcgm-exporter
使用 Go 綁定 從 DCGM 收集 GPU 遙測數據,然后為 Prometheus 公開指標以使用 http 端點(/metrics
)進行提取
dcgm-exporter
也是可配置的。您可以使用 .csv 格式的輸入配置文件,自定義 DCGM 要收集的 GPU 指標。
Kubernetes 集群中的每個 pod GPU 指標
dcgm-exporter
收集節點上所有可用 GPUs 的指標。然而,在 Kubernetes 中,當一個 pod 請求 GPU 資源時,您不一定知道節點中的哪個 GPUs 將被分配給一個 pod 。從 v1 . 13 開始, kubelet
添加了一個設備監視功能,可以使用 pod 資源套接字找到分配給 pod — 的 pod 名稱、 pod 名稱空間和設備 ID 的設備。
dcgm-exporter
中的 http 服務器連接到 kubelet
pod resources 服務器( /var/lib/kubelet/pod-resources
),以標識在 pod 上運行的 GPU 設備,并將 GPU 設備 pod 信息附加到收集的度量中。

設置 GPU 監控解決方案
下面是一些設置 dcgm-exporter
的示例。如果您使用的是 NVIDIA GPU 操作員 ,那么 dcgm-exporter
是作為操作員的一部分部署的組件之一。
文檔包括 建立 Kubernetes 集群 的步驟。為了簡潔起見,請快速前進到使用 NVIDIA 軟件組件運行 Kubernetes 集群的步驟,例如,驅動程序、容器運行時和 Kubernetes 設備插件。您可以使用 Prometheus Operator 來部署 Prometheus ,它還可以方便地部署 Grafana 儀表板。在本文中,為了簡單起見,您將使用單節點 Kubernetes 集群。
設置 普羅米修斯運營商目前提供的社區頭盔圖 時,必須遵循 將 GPU 遙測技術集成到 Kubernetes 中 中的步驟。必須為外部訪問公開 Grafana ,并且必須將 prometheusSpec.serviceMonitorSelectorNilUsesHelmValues
設置為 false 。
簡而言之,設置監視包括運行以下命令:
$ helm repo add prometheus-community \ https://prometheus-community.github.io/helm-charts $ helm repo update $ helm inspect values prometheus-community/kube-prometheus-stack > /tmp/kube-prometheus-stack.values # Edit /tmp/kube-prometheus-stack.values in your favorite editor # according to the documentation # This exposes the service via NodePort so that Prometheus/Grafana # are accessible outside the cluster with a browser $ helm install prometheus-community/kube-prometheus-stack \ --create-namespace --namespace prometheus \ --generate-name \ --set prometheus.service.type=NodePort \ --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
此時,您的集群應該看起來像下面這樣,其中所有的 Prometheus pods 和服務都在運行:
$ kubectl get pods -A NAMESPACE???? NAME????????????????????????????????????????????????????????????? READY?? STATUS??? RESTARTS?? AGE kube-system?? calico-kube-controllers-8f59968d4-zrsdt?????????????????????????? 1/1???? Running?? 0????????? 18m kube-system?? calico-node-c257f???????????????????????????????????????????????? 1/1???? Running?? 0????????? 18m kube-system?? coredns-f9fd979d6-c52hz? ?????????????????????????????????????????1/1???? Running?? 0????????? 19m kube-system?? coredns-f9fd979d6-ncbdp?????????????????????????????????????????? 1/1???? Running?? 0????????? 19m kube-system?? etcd-ip-172-31-27-93?????????????????????????????????? ???????????1/1???? Running?? 1????????? 19m kube-system?? kube-apiserver-ip-172-31-27-93??????????????????????????????????? 1/1???? Running?? 1????????? 19m kube-system?? kube-controller-manager-ip-172-31-27-93?????????????????????????? 1/1???? Running?? 1????????? 19m kube-system?? kube-proxy-b9szp????????????????????????????????????????????????? 1/1???? Running?? 1????????? 19m kube-system?? kube-scheduler-ip-172-31-27-93??????????????????????????????????? 1/1???? Running?? 1????????? 19m kube-system?? nvidia-device-plugin-1602308324-jg842???????????????????????????? 1/1???? Running?? 0????????? 17m prometheus??? alertmanager-kube-prometheus-stack-1602-alertmanager-0??????????? 2/2???? Running?? 0????????? 92s prometheus??? kube-prometheus-stack-1602-operator-c4bc5c4d5-f5vzc?????????????? 2/2???? Running?? 0????????? 98s prometheus??? kube-prometheus-stack-1602309230-grafana-6b4fc97f8f-66kdv???????? 2/2???? Running?? 0????????? 98s prometheus??? kube-prometheus-stack-1602309230-kube-state-metrics-76887bqzv2b?? 1/1???? Running?? 0????????? 98s prometheus??? kube-prometheus-stack-1602309230-prometheus-node-exporter-rrk9l?? 1/1???? Running?? 0????????? 98s prometheus??? prometheus-kube-prometheus-stack-1602-prometheus-0??????????????? 3/3???? Running?? 1????????? 92s ? ? $ kubectl get svc -A NAMESPACE???? NAME??????????????????????????????????????????????????????? TYPE??????? CLUSTER-IP?????? EXTERNAL-IP?? PORT(S)??????????????????????? AGE default?????? kubernetes????????????????????????????????????????????????? ClusterIP?? 10.96.0.1??????? <none> ???????443/TCP??????????????????????? 20m kube-system?? kube-dns??????????????????????????????????????????????????? ClusterIP?? 10.96.0.10?????? <none>??????? 53/UDP,53/TCP,9153/TCP???????? 20m kube-system?? kube-prometheus-stack-1602-coredns????????????? ????????????ClusterIP?? None???????????? <none>??????? 9153/TCP?????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-controller-manager????????? ClusterIP?? None???????????? <none>??????? 10252/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-etcd??????????????????????? ClusterIP?? None???????????? <none>??????? 2379/TCP?????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-proxy?????????????????????? ClusterIP?? None???????????? <none>?? ?????10249/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-scheduler?????????????????? ClusterIP?? None???????????? <none>??????? 10251/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kubelet??????????? ??????????????ClusterIP?? None???????????? <none>??????? 10250/TCP,10255/TCP,4194/TCP?? 2m12s prometheus??? alertmanager-operated?????????????????????????????????????? ClusterIP?? None???????????? <none>??????? 9093/TCP,9094/TCP,9094/UDP???? 2m12s prometheus??? kube-prometheus-stack-1602-alertmanager???????????????????? ClusterIP?? 10.104.106.174?? <none>??????? 9093/TCP?????????????????????? 2m18s prometheus??? kube-prometheus-stack-1602-operator??????????????? ?????????ClusterIP?? 10.98.165.148??? <none>??????? 8080/TCP,443/TCP?????????????? 2m18s prometheus??? kube-prometheus-stack-1602-prometheus?????????????????????? NodePort??? 10.105.3.19????? <none>??????? 9090:30090/TCP???????????????? 2m18s prometheus?? ?kube-prometheus-stack-1602309230-grafana??????????????????? ClusterIP?? 10.100.178.41??? <none>??????? 80/TCP???????????????????????? 2m18s prometheus??? kube-prometheus-stack-1602309230-kube-state-metrics???????? ClusterIP?? 10.100.119.13??? <none>????? ??8080/TCP?????????????????????? 2m18s prometheus??? kube-prometheus-stack-1602309230-prometheus-node-exporter?? ClusterIP?? 10.100.56.74???? <none>??????? 9100/TCP?????????????????????? 2m18s prometheus??? prometheus-operated????????????????????????????? ???????????ClusterIP?? None???????????? <none>??????? 9090/TCP?????????????????????? 2m12s
安裝 DCGM-Exporter
下面是如何開始安裝 dcgm-exporter
來監視 GPU 的性能和利用率。您可以使用頭盔圖表來設置 dcgm-exporter
。首先,添加 Helm 回購:
$ helm repo add gpu-helm-charts \ https://nvidia.github.io/gpu-monitoring-tools/helm-charts
$ helm repo update
然后,使用 Helm 安裝圖表:
$ helm install \ ?? --generate-name \ ?? gpu-helm-charts/dcgm-exporter
可以使用以下命令觀察展開:
$ helm ls NAME??????????????????????????? NAMESPACE?????? REVISION??????? APP VERSION dcgm-exporter-1-1601677302????? default???????? 1?????????????? dcgm-exporter-1.1.0???????????? 2.0.10 nvidia-device-plugin-1601662841 default???????? 1????????? nvidia-device-plugin-0.7.0????? 0.7.0
普羅米修斯和格拉法納的服務應公開如下:
$ kubectl get svc -A NAMESPACE???? NAME????????????????????????????????????????????????????? TYPE??????? CLUSTER-IP?????? EXTERNAL-IP?? PORT(S)??????????????????????? AGE default?????? dcgm-exporter???????????????????????????????????????????? ClusterIP?? 10.99.34.128???? <none>??????? 9400/TCP?????????????????????? 43d default?????? kubernetes????????????????????????????????????????????????? ClusterIP?? 10.96.0.1??????? <none>??????? 443/TCP??????????????????????? 20m kube-system?? kube-dns????? ??????????????????????????????????????????????ClusterIP?? 10.96.0.10?????? <none>??????? 53/UDP,53/TCP,9153/TCP???????? 20m kube-system?? kube-prometheus-stack-1602-coredns????????????????????????? ClusterIP?? None???????????? <none>??????? 9153/TCP?????? ????????????????2m18s kube-system?? kube-prometheus-stack-1602-kube-controller-manager????????? ClusterIP?? None???????????? <none>??????? 10252/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-etcd??????????????????????? ClusterIP?? None???????????? <none>??????? 2379/TCP?????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-proxy?????????????????????? ClusterIP?? None??????????? ?<none>??????? 10249/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kube-scheduler???? ??????????????ClusterIP?? None???????????? <none>??????? 10251/TCP????????????????????? 2m18s kube-system?? kube-prometheus-stack-1602-kubelet????????????????????????? ClusterIP?? None???????????? <none>??????? 10250/TCP,10255/TCP,4194/TCP?? 2m12s prometheus??? alertmanager-operated?????????????????????????????????????? ClusterIP?? None???????????? <none>??????? 9093/TCP,9094/TCP,9094/UDP???? 2m12s prometheus??? kube-prometheus-stack-1602-alertmanager???????????????????? ClusterIP?? 10.104.106.174?? <none> ???????9093/TCP?????????????????????? 2m18s prometheus??? kube-prometheus-stack-1602-operator???????????????????????? ClusterIP?? 10.98.165.148??? <none>??????? 8080/TCP,443/TCP?????????????? 2m18s prometheus??? kube-prometheus-stack-1602-prometheus?????? ????????????????NodePort??? 10.105.3.19????? <none>??????? 9090:30090/TCP???????????????? 2m18s prometheus??? kube-prometheus-stack-1602309230-grafana??????????????????? ClusterIP?? 10.100.178.41??? <none>??????? 80:32032/TCP?????????????????? 2m18s prometheus??? kube-prometheus-stack-1602309230-kube-state-metrics???????? ClusterIP?? 10.100.119.13??? <none>??????? 8080/TCP?????????????????????? 2m18s prometheus??? kube-prometheus-stack-1602309230-prometheus-node-exporter?? ClusterIP?? 10.100.56.74???? <none>??????? 9100/TCP?????????????????????? 2m18s prometheus??? prometheus-operated???????????????????????????????????????? ClusterIP?? None???????????? <none>??????? 9090/TCP?????????????????????? 2m12s
使用在端口 32032 公開的 Grafana 服務,訪問 Grafana 主頁。使用普羅米修斯圖表中可用的憑據登錄到儀表板: prometheus.values
中的 adminPassword
字段。
現在要為 GPU 度量啟動 Grafana 儀表板,請從 數一數儀表板。 導入引用的 NVIDIA 儀表板。
使用 DCGM 儀表板

現在運行一些 GPU 工作負載。為此, DCGM 包括一個名為 dcgmproftester 的 CUDA 負載生成器。它可以用來生成確定性的 CUDA 工作負載,用于讀取和驗證 GPU 度量。我們有一個集裝箱化的 dcgmproftester
,可以在 Docker 命令行上運行。這個例子生成一個半精度( FP16 )矩陣乘法( GEMM ),并使用 GPU 上的張量核。
產生負載
要生成負載,必須首先下載 DCGM 并將其容器化。下面的腳本創建一個可用于運行 dcgmproftester
的容器。此容器可在 NVIDIA DockerHub 存儲庫中找到。
#!/usr/bin/env bash set -exo pipefail ? mkdir -p /tmp/dcgm-docker pushd /tmp/dcgm-docker ? cat > Dockerfile <<EOF ARG BASE_DIST ARG CUDA_VER FROM nvidia/cuda:\${CUDA_VER}-base-\${BASE_DIST} LABEL io.k8s.display-name="NVIDIA dcgmproftester" ? ARG DCGM_VERSION ? WORKDIR /dcgm RUN apt-get update && apt-get install -y --no-install-recommends \ ??? libgomp1 \ ??? wget && \ ??? rm -rf /var/lib/apt/lists/* && \ ??? wget --no-check-certificate https://developer.download.nvidia.com/compute/redist/dcgm/\${DCGM_VERSION}/DEBS/datacenter-gpu-manager_\${DCGM_VERSION}_amd64.deb && \ ??? dpkg -i datacenter-gpu-manager_*.deb && \ ??? rm -f datacenter-gpu-manager_*.deb ? ENTRYPOINT ["/usr/bin/dcgmproftester11"] EOF ? DIR=. DCGM_REL_VERSION=2.0.10 BASE_DIST=ubuntu18.04 CUDA_VER=11.0 IMAGE_NAME=nvidia/samples:dcgmproftester-$DCGM_REL_VERSION-cuda$CUDA_VER-$BASE_DIST ? ? docker build --pull \ ??????? -t "$IMAGE_NAME" \ ??????? --build-arg DCGM_VERSION=$DCGM_REL_VERSION \ ??????? --build-arg BASE_DIST=$BASE_DIST \ ??????? --build-arg CUDA_VER=$CUDA_VER \ ??????? --file Dockerfile \ ??????? "$DIR" ? popd
在將容器部署到 Kubernetes 集群之前,請嘗試在 Docker 中運行它。在本例中,通過指定 -t 1004
,使用張量核心觸發 FP16 矩陣乘法,并運行測試 -d 45
( 45 秒)。您可以通過修改 -t
參數來嘗試運行其他工作負載。
$ docker run --rm --gpus all --cap-add=SYS_ADMIN nvidia/samples:dcgmproftester-2.0.10-cuda11.0-ubuntu18.04 --no-dcgm-validation -t 1004 -d 45 ? Skipping CreateDcgmGroups() since DCGM validation is disabled CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR: 1024 CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT: 40 CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_MULTIPROCESSOR: 65536 CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR: 7 CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR: 5 CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH: 256 CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE: 5001000 Max Memory bandwidth: 320064000000 bytes (320.06 GiB) CudaInit completed successfully. ? Skipping WatchFields() since DCGM validation is disabled TensorEngineActive: generated ???, dcgm 0.000 (27605.2 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28697.6 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28432.8 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28585.4 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28362.9 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28361.6 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28448.9 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28311.0 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28210.8 gflops) TensorEngineActive: generated ???, dcgm 0.000 (28304.8 gflops)
將此計劃到您的 Kubernetes 集群上,并在 Grafana 儀表板中查看適當的度量。下面的代碼示例使用容器的適當參數構造此 podspec :
cat << EOF | kubectl create -f - ?apiVersion: v1 ?kind: Pod ?metadata: ?? name: dcgmproftester ?spec: ?? restartPolicy: OnFailure ?? containers: ?? - name: dcgmproftester11 ???? image: nvidia/samples:dcgmproftester-2.0.10-cuda11.0-ubuntu18.04 ???? args: ["--no-dcgm-validation", "-t 1004", "-d 120"] ???? resources: ?????? limits: ????????? nvidia.com/gpu: 1 ???? securityContext: ?????? capabilities: ????????? add: ["SYS_ADMIN"] ? EOF
您可以看到 dcgmproftester
pod 正在運行,然后在 Grafana 儀表板上顯示度量。 GPU 利用率( GrActive )已達到 98% 的峰值。您還可能會發現其他指標很有趣,比如 power 或 GPU 內存。
$ kubectl get pods -A NAMESPACE???? NAME????????????????????????????????????????????????????????????? READY?? STATUS??? RESTARTS?? AGE ... default?????? dcgmproftester??????????????????????????????????????????????????? 1/1???? Running?? 0???????? ?6s ...

驗證 GPU 指標
DCGM 最近增加了一些設備級指標。其中包括細粒度的 GPU 利用率指標,可以監視 SM 占用率和 Tensor 核心利用率。有關詳細信息,請參閱 DCGM 用戶指南 中的 分析指標 。為了方便起見,當您使用 Helm 圖表部署 dcgm-exporter
時,它被配置為默認收集這些度量。
圖 5 顯示了在 Prometheus 儀表板中驗證 dcgm-exporter
提供的評測指標。

您可以定制 Grafana 儀表板以包含 DCGM 的其他指標。在本例中,通過編輯 repo 上可用的 JSON 伯爵夫人 文件,將 Tensor 核心利用率添加到儀表板中。你也可以使用網頁界面。請隨意修改儀表板。
此儀表板包括 Tensor 核心利用率。您可以進一步自定義它。重新啟動 dcgmproftester
容器后,您可以看到 T4 上的張量核心已達到約 87% 的利用率:

請隨意修改 JSON 儀表板,以包含 DCGM 支持的其他 GPU 指標。支持的 GPU 指標在 DCGM DCGM API Documentation 中可用。通過使用 GPU 指標作為定制指標和普羅米修斯適配器,您可以使用 臥式吊艙自動標度機 根據 GPU 利用率或其他指標來縮放吊艙的數量。
概要
要從 dcgm-exporter
開始,并將監視解決方案放在 Kubernetes 上,無論是在前提還是在云中,請參閱 將 GPU 遙測技術集成到 Kubernetes 中 ,或將其部署為 NVIDIA GPU 操作員 的一部分。官方的 GitHub 代碼庫是 NVIDIA/gpu-monitoring-tools ,我們很樂意聽到您的反饋!可以在 NVIDIA/gpu-monitoring-tools/issues 處自由地文件問題或新功能請求。
?