1、背景介紹node
對於SRE團隊來講,實現監控AI、高性能計算平臺上大規模GPU資源,相當重要。SRE團隊能夠經過GPU指標瞭解工做負載等相關性能,從而優化資源分配,提高資源利用率及異常診斷,以提升數據中心資源的總體效能。除了SRE及基礎設施團隊以外,無論你是從事GPU加速方向的研究人員,仍是數據中心架構師,均可以經過相關監控指標,瞭解GPU利用率和工做飽和度以進行容量規劃及任務調度等。
隨着AI/ML工做負載的容器化,調度平臺採用具有動態擴縮特性的Kubernetes解決方案,針對其監控的急迫性日益提高。在這篇文章中,咱們將介紹NVIDIA數據中心GPU管理器(DCGM),以及如何將其集成到Prometheus和Grafana等開源工具中,以實現Kubernetes的GPU監控的總體解決方案。
複製代碼
2、NVIDIA DCGMgit
NVIDIA DCGM是用於管理和監控基於Linux系統的NVIDIA GPU大規模集羣的一體化工具。它是一個低開銷的工具,提供多種能力,包括主動健康監控、診斷、系統驗證、策略、電源和時鐘管理、配置管理和審計等。github
DCGM提供用於收集GPU遙測的API。特別值得關注的是GPU利用率指標、內存指標和流量指標。DCGM提供了各類語言的客戶端,如C和Python。對於與容器生態系統的集成,提供基於DCGM APIs的Go綁定實現。redis
2、DCGM exporterdocker
監控系統一般由指標採集器、用於存儲指標的時間序列數據庫和可視組件組成。例如CNCF畢業項目Prometheus,它和Grafana一塊兒構成監控集成方案。其中Prometheus還包括Alertmanager來建立和管理警報。Prometheus、kube-state-metrics及node_exporter一塊兒部署,以獲取Kubernetes API對象的集羣指標和CPU利用率等節點指標。下圖爲Prometheus的示例架構。
複製代碼
在前面介紹的Go API基礎上,能夠經過DCGM向Prometheus暴露GPU指標。NVIDIA爲此構建了dcgm-exporter的項目。數據庫
dcgm-exporter 使用 Go 綁定從 DCGM 收集 GPU 遙測數據,而後經過 http 接口 (/metrics) 向 Prometheus 暴露指標。ubuntu
dcgm-exporter能夠經過使用csv格式的配置文件來定製DCGM收集的GPU指標。api
3、Kubernetes集羣中的每一個節點GPU指標bash
dcgm-exporter收集了節點上全部可用GPU的指標。然而,在Kubernetes中,當一個節點請求GPU資源時,可能不能肯定哪些GPU會被分配給pod。從v1.13開始,Kubelet增長了一個設備監控功能,能夠經過pod-resources套接字瞭解分配給pod的設備,其中包括pod名稱、pod命名空間和設備ID。markdown
dcgm-exporter中的http服務鏈接到kubelet中的pod-resources服務(/var/lib/kubelet/pod-resources)來識別pod上運行的GPU設備,並將GPU設備的pod相關信息添加到收集的指標中。
4、GPU監控方案
下面是一些設置dcgm-exporter的示例。若是使用NVIDIA GPU Operator,那麼dcgm-exporter一樣是部署組件之一。
文檔中包含了設置Kubernetes集羣的步驟。爲了簡潔起見,假定已經存在一個運行着NVIDIA軟件組件的Kubernetes集羣,例如,驅動程序、容器運行時和Kubernetes設備插件等。在使用Prometheus Operator部署Prometheus時,還能夠方便地部署Grafana。在該篇文章中,爲了簡單起見,使用了單節點Kubernetes集羣。
在設置社區提供的Prometheus Operator的Helm chart時,必須暴露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
$ 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
複製代碼
Prometheus和Grafana服務暴露以下:
$ 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 chart中設置的憑證登陸到儀表板:prometheus.values中的adminPassword字段。
如今要啓動一個用於GPU指標的Grafana儀表板,請從Grafana儀表板(grafana.com/grafana/das…
查看DCGM指標
如今運行一些GPU工做負載,爲此,DCGM社區提供了一個名爲dcgmproftester的CUDA負載生成器,它能夠用來生成肯定性的CUDA工做負載,用於讀取和驗證GPU指標。
要生成一個Pod,首先必須下載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來使用Tensor Cores觸發FP16矩陣乘法,並以-d 45(45秒)的速度運行測試。您能夠經過修改-t參數來嘗試運行其餘工做負載。
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儀表板觀測相應的指標。下面的代碼示例:
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%的利用率峯值,可能還會發現其餘有趣的指標,好比功率或GPU內存。
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
...
default dcgmproftester 1/1 Running 0 6s
...
複製代碼
驗證指標
DCGM最近增長了一些設備級指標。其中包括細粒度的GPU利用率指標,能夠監控SM佔用率和Tensor Core利用率。有關更多信息,能夠查看DCGM用戶指南中的Profiling Metrics。
下圖顯示了 Prometheus獲取的由dcgm-exporter 提供的監控指標。
您能夠自定義Grafana儀表板,以包含DCGM的其餘指標。在這種狀況下,經過編輯 repo 上提供的 Grafana JSON 文件將 Tensor Core 利用率添加到儀表板中,也可使用Grafana的Web界面進行編輯。
下面的儀表板包括Tensor Core利用率。從新啓動dcgmproftester容器後,你能夠看到T4上的Tensor Core已經達到了約87%的利用率。
經過將GPU指標做爲自定義指標和Prometheus Adapter,可使用Horizontal Pod Autoscaler根據GPU利用率或其餘指標來擴展Pod數量。
4、參考資料
一、monitoring