KubernetesのGPUノードをPrometheusで監視する


はじめに

近年のDeep Learningブームの中で、多数のGPUノードをKubernetesで管理し、複数人で共有するといった運用形態を良く耳にするようになりました。弊社でもオンプレミス環境にGPUクラスタを構え、Deep Learningを用いたAI開発を行っています(開発プラットフォームとしてはOSSのKAMONOHASHIを利用しています)。

GPUクラスタを共有し利用していく中で、GPUノードの利用状況をメトリクスとして収集し、過去の利用過程を可視化したいという要望が出てきました。そこでNVIDIA DCGM exporter for PrometheusPrometheusを用いて、GPUのメトリクスを収集してみました。

なお、本記事で利用するファイルはGitHubに置いています。

ゴール

GPUノードが含まれるKubernetesクラスタに、PrometheusとDCGM exporterを導入し、PrometheusでGPUのメトリクスが収集できるようにします。

バージョン情報

利用した各コンポーネントのバージョンは以下の通りです。

Prometheus, nginx-ingressに関してはHelmを用いて導入しました。

クラスタの構成

クラスタに含まれるノードは、以下のものとします。

  • master: Kubernetesのmasterノード
  • gpu1: NVIDIA Tesla K80搭載のGPUノード
  • gpu2: NVIDIA Tesla K80搭載のGPUノード
  • kamonohashi: KAMONOHASHIで利用のノード。今回は関係なし

※既存のKAMONOHASHIクラスタを利用しています。KAMONOHASHI導入時、Kubernetesはkubesprayを利用して構築しています。

今回はmasterノードにPrometheusをデプロイし、Ingressを通してアクセスします。Ingress ControllerにはNginx Ingress Controllerを利用します。

またDCGM exporterが動く要件は以下が提示されているため、各GPUノードでこれらの要件を満たすようにしておきます。

Prerequisites

NVIDIAが提供しているGPUのモニタリングツール

NVIDIAが提供しているGPUのモニタリングツールは、GitHubのNVIDIA/gpu-monitoring-toolsから入手できます。この中のNVIDIA DCGM exporter for Prometheusが、PrometheusでGPUのメトリクスを取る際のexporterとして利用できるものとなっています。DCGMはNVIDIA Data Center GPU Managerの略で、GPUクラスタのメトリクスを取るために用意されているツール群のことを表します。

このリポジトリですが、少し中身が分かりづらいため、ここで整理しておきます。
NVIDIA DCGM exporter for Prometheus内のk8s/node-exporterが、exporterのDaemonSetのマニフェストが格納されたディレクトリとなっています(k8s/pod-gpu-metrics-exporterは、exporter自体のソースコードが格納されています)。

k8s/node-exporter内には、以下の3つのマニフェストファイルが格納されています。

gpu-node-exporter-daemonset.yaml
GPUノードのメトリクスをCPU等の情報も含めて取得するexporterのDaemonSet

gpu-only-node-exporter-daemonset.yaml
GPUノードのメトリクスをGPU情報のみを取得するexporterのDaemonSet

pod-gpu-node-exporter-daemonset.yaml
PodごとのGPU利用状況のメトリクスを取得するexporterのDaemonSet

これらのDaemonSetは、それぞれ以下のexporterの組み合わせにより構成されています。

prometheus/node-exporter
Prometheusが提供している一般的なexporterです。

nvidia/dcgm-exporter
NVIDIAが提供しているGPUノードのメトリクスを取るexporterです。このexporterを用いることで、GPUノードごとのGPU利用率やGPUメモリ利用量が取得できます。prometheus/node-exporterとこのexporterを統合したものが、gpu-node-exporter-daemonsetgpu-only-node-exporter-daemonsetで利用されています。

nvidia/pod-gpu-metrics-exporter
PodごとのGPU利用状況のメトリクスを取るexporterです。このexporterを用いることで、GPUノードに立っているPodごとのGPU利用率やGPUメモリ利用量が取得できます。prometheus/node-exporterおよびnvidia/dcgm-exporterと、このexporterを統合したものが、pod-gpu-node-exporter-daemonsetで利用されています。
kubeletを利用してpodの情報を取得するため、FeatureGatesのKubeletPodResourcesが有効になっている必要があります(Kubernetes v1.15以降はデフォルトで有効になっています)

本記事ではpod-gpu-node-exporter-daemonset.yamlを利用して、PodごとのGPU利用状況のメトリクスを取得してみます。

手順

1. kubeletの設定変更

今回用いたKubernetesはv1.14.1であるため、PodごとのGPU利用状況のメトリクスを取得するためには、各GPUノードにおいてkubeletのFeatureGatesの機能を有効にする必要があります。
各GPUノードで/etc/systemd/system/kubelet.serviceを編集し、ExecStartの部分を修正します。

ExecStart=/usr/local/bin/kubelet \
+                --feature-gates KubeletPodResources=true \

そして以下のコマンドでkubeletを再起動します。

systemctl daemon-reload
systemctl restart kubelet

これらの作業により、上述のexporterがPodの情報を取得できるようになります。

2. namespaceの作成

今回デプロイするリソース用のnamespaceを作成します。名前はmonitoringとします。

kubectl create namespace monitoring

3. GPUノードに対するラベル付与

pod-gpu-node-exporter-daemonsetではnodeSelectorとしてhardware-type: NVIDIAGPUが設定されており、このラベルが付与されたノードに対してexporterが配置される設定となっています。
そこで以下のように、GPUノードに対してラベル付けを行います(<gpu-node-name>をgpu1などのgpuノードのホスト名に変更)。

kubectl label nodes <gpu-node-name> hardware-type=NVIDIAGPU

ラベルの付与状況は、以下のコマンドで確認できます。

kubectl get nodes --show-labels

4. Prometheusのデータ保存先を作成

Prometheusをデプロイする際には、収集したデータの保存先を指定する必要があります。今回はmasterノードの/var/lib/prometheus配下に保存することとします。以下のコマンドでディレクトリを作成し、ownerをnobodyに設定します。Prometheus serverはnobodyユーザで実行されるため、ownerの変更が必要となります。

mkdir /var/lib/prometheus
chown nobody /var/lib/prometheus

5. 各種リソースのデプロイ

以下のリソースをデプロイします。利用したファイルはGitHubに置いています

  • GPUノード用のexporterを配置するためのDaemonSet(pod-gpu-node-exporter-daemonset.yaml)
  • exporterのPodにアクセスするためのservice(exporter-service.yaml)
  • Prometheusで利用するPersistent Volume, Persistent Volume Claim(prometheus-pv-pvc.yaml)

GPUノード用のexporterに関しては、元のリポジトリにあるpod-gpu-node-exporter-daemonset.yamlのnamespaceをkube-systemからmonitoringに変更したものを用います。またPrometheusがexporterのPodから情報を収集できるようにするためserviceも作成します。さらにPrometheusのデータ保存用のPVおよびPVCを、8GB(Prometheusチャートのデフォルト値)の容量で作成します。

これら3つのマニフェストファイルを以下のコマンドで適用します。

kubectl apply -f pod-gpu-node-exporter-daemonset.yaml -f exporter-service.yaml -f prometheus-pv-pvc.yaml

exporterのデプロイ後、正常にGPUノードのメトリクスが出力されているかは以下のコマンドで確認できます。

curl <gpu-node-name>:9100/metrics | grep dcgm

dcgm_gpu_utilization等が出力されていれば、正常にexporterが起動しています。一度ここで確認することをおすすめします。

6. Prometheusのインストール

Helmを利用してPrometheusのインストールを行います。
以下のコマンドでprometheusの設定ファイルをダウンロードし、編集します。

helm inspect values stable/prometheus > prometheus-values.yaml

今回は、ひとまず動作させることを目的にしているため、ほぼ全ての機能を無効化した状態でデプロイします。

  • Prometheus serverのみ有効化
  • http://master-hostname/prometheusのような形でアクセスするためにprefixURLとbaseURLを変更
  • prometheus serverのingressを有効化し、ingress.classとしてprometheus-nginxを指定
  • masterノードにデプロイするようnodeSelectorを設定
  • persistentVolumeとして上記で作成したものを指定

編集が完了後、以下のコマンドでPrometheusのインストールを行います。

helm install --name prometheus --namespace monitoring --version 9.3.1 -f prometheus-values.yaml stable/prometheus

7. Ingress Controllerのインストール

Prometheus ServerのIngress用に、Nginx Ingress Controllerをインストールします。
以下のコマンドで設定ファイルをダウンロードし、編集します。

helm inspect values stable/nginx-ingress > nginx-ingress-values.yaml

編集内容は次のようなものです。

  • ingressClassをprometheus-nginxに変更
  • scopeを有効にし、namespaceとしてmonitoringを指定
  • defaultBackendServiceとしてmonitoring/prometheus-serverを指定
  • masterノードにデプロイするようnodeSelectorを設定
  • externalIPsとしてmasterノードのIPを指定

編集が完了後、以下のコマンドでIngress Controllerのインストールを行います

helm install stable/nginx-ingress --name prometheus-nginx --namespace monitoring --version 1.24.7 -f nginx-ingress-values.yaml

8. Prometheusの利用

ブラウザでPrometheusデプロイ時に設定したURLにアクセスすることで、Prometheusでのメトリクス取得状況を見ることができます。gpu関連のメトリクスはdcgm_...というもので取得できます。

まとめ

NVIDIA DCGM exporter for PrometheusとPrometheusを組み合わせることで、GPUリソースの利用状況の監視が可能となりました。Grafanaと組み合わせることで、Prometheusでの収集結果を美しく可視化することも可能です。

実際に運用するには、メトリクスの保存領域のサイズ等を詳しく検討する必要がありますが、似たようなことを実現したい方の参考になれば幸いです。