【第7回】ローカルLLM環境の監視(Prometheus/Grafana)とセキュリティ設計:AIインフラを可視化する

本連載もいよいよ終盤です。第1回から第6回までを通じて、AlmaLinux 9上に「vLLM」を用いた高スループット推論サーバー、そして「Qdrant」を用いたベクトルデータベースとEmbeddingサーバーからなる「RAG(検索拡張生成)基盤」を構築してきました。インフラエンジニアの視点で設計されたこれらのマイクロサービスは、エンタープライズの業務要件に耐えうる堅牢な生成AIアーキテクチャを形成しています。

しかし、システムが完成し、本番環境でユーザーに開放された瞬間から、インフラエンジニアにとって最も恐ろしい課題が浮上します。それは「AIインフラのブラックボックス化」です。

コウ君

リナックス先生、社内リリースしたRAGシステムですが、突然「チャットボットからの返答が1分以上返ってこない」という問い合わせが殺到しました。サーバーに入って nvidia-smi や top コマンドを叩いても、GPUメモリは埋まっているしCPUも動いているように見えます。どこがボトルネックになっているのか、全く分かりません……!

リナックス先生

AIインフラのトラブルシューティングにおいて、OSの標準コマンドだけで原因を特定するのは不可能です。レスポンス遅延の原因は、vLLMのKVキャッシュが枯渇してリクエストがキューに溜まっているのか、Qdrantのベクトル検索I/Oで詰まっているのか、あるいは単なるネットワークの輻輳なのか。これらをリアルタイムで特定し、異常を事前に検知するための「可視化(オブザーバビリティ)」と、それを安全に運用するための「セキュリティ設計」が絶対に必要になります。

本記事「【第7回】ローカルLLM環境の監視(Prometheus/Grafana)とセキュリティ設計」では、クラウドネイティブな監視スタックのデファクトスタンダードである「Prometheus」と「Grafana」、そしてNVIDIA公式のメトリクスエクスポーターである「DCGM-Exporter」を用いて、ローカルLLM特有のパフォーマンス指標を可視化するエンタープライズ監視基盤を構築します。さらに、AIシステムの脆弱性を突く攻撃から社内インフラを守るためのネットワーク・セキュリティ設計のベストプラクティスを徹底解説します。


1. なぜローカルLLMにエンタープライズ級の監視が必要なのか?

Webサーバー(NginxやApache)やリレーショナルデータベース(MySQL等)の運用監視であれば、CPU使用率、メモリ空き容量、ディスクI/O、HTTPステータスコード(500エラー等)といった標準的なメトリクスを取得するだけで、おおよその健康状態(ヘルス)を把握できます。しかし、ローカルLLMのインフラにおいては、これらの「レガシーな監視指標」だけでは全く不十分です。

1.1. リソース枯渇とブラックボックス化の恐怖

生成AIシステム特有のインフラ障害は、OSのレイヤーではなく、GPU(VRAM)の内部空間や、推論エンジンのキューイングメカニズムの奥深くで発生します。

  • OOM(Out of Memory)のサイレント・クラッシュ: vLLMやllama.cppはVRAMを極限まで使い切るように設計されているため、少しでもコンテキストサイズやバッチサイズを見誤ると、カーネルログにも残さずに無言でプロセスが落ちることがあります。
  • KVキャッシュのフラグメンテーション(断片化): VRAM使用率が100%に張り付いている状態でも、「効率的に計算が行われている100%」なのか、「KVキャッシュが断片化して新しいリクエストを受け付けられず、ひたすらキューに積まれている(レスポンス遅延)100%」なのかは、nvidia-smi コマンドからは判別できません。
  • サーマルスロットリングと電力消費: 高価なGPUをフル稼働させると、発熱によってクロックダウン(性能低下)が発生します。サーバーラック全体の空調要件や電力リミットを管理しなければ、ハードウェアの寿命を極端に縮めることになります。

1.2. 監視すべき4つのコンポーネント

本連載で構築したRAG基盤では、以下の4つのレイヤーからメトリクスを収集し、一元的に相関関係を分析できる「オブザーバビリティ(可観測性)」を確立する必要があります。

  1. ハードウェア・OSレイヤー: CPU、RAM、ネットワークI/O、ストレージI/O(Node-Exporter)
  2. GPUレイヤー: VRAM使用量、GPU使用率、温度、消費電力、ストリーミングマルチプロセッサ(SM)クロック(DCGM-Exporter)
  3. 推論エンジンレイヤー(vLLM): バッチサイズ、KVキャッシュ使用率、トークン生成速度(Tokens/sec)、キュー待機数
  4. ベクトルDBレイヤー(Qdrant): 検索レイテンシ、gRPC接続数、HNSWインデックスのメモリサイズ

2. AIハードウェア監視:DCGM-ExporterとNode-Exporterの導入

監視基盤の構築にあたり、まずは監視対象のサーバー(各種コンテナが稼働しているAlmaLinuxホスト)から各種の数値を外部に公開(エクスポーズ)するためのエージェントを立ち上げます。これらはすべてPodmanコンテナ(Quadlet)としてデプロイします。

2.1. Node-Exporterの構築(OSメトリクス)

Linux OSの基本的なメトリクス(CPU, メモリ, ディスクI/O等)を取得するため、Prometheus公式の node-exporter を稼働させます。

cat << 'EOF' | sudo tee /etc/containers/systemd/node-exporter.container
[Unit]
Description=Prometheus Node Exporter
After=network-online.target

[Container]
Image=quay.io/prometheus/node-exporter:latest
ContainerName=node-exporter
# ホストのネットワーク名前空間を共有(ホストの全メトリクスを取得するため)
Network=host
# ホストのファイルシステムを読み取り専用でマウント
Volume=/:/rootfs:ro
Volume=/var/run:/var/run:ro
Volume=/sys:/sys:ro
Volume=/var/lib/docker:/var/lib/docker:ro
Exec=--path.rootfs=/rootfs

[Install]
WantedBy=multi-user.target
EOF

2.2. DCGM-Exporterの構築(GPUメトリクス)

コウ君

GPUの監視って、定期的にシェルスクリプトで nvidia-smi を実行してテキストをパースするしかないと思ってました。

リナックス先生

その手法はインフラの現場でよく見かけますが、負荷が高くデータも欠損しやすいためアンチパターンです。エンタープライズ環境では、NVIDIAが公式に提供している「DCGM (Data Center GPU Manager) Exporter」を使用します。これにより、GPUハードウェアから直接、高精度かつ低負荷でPrometheus形式のメトリクスを抽出できます。

DCGM-Exporterを稼働させるQuadletユニットを作成します。コンテナからGPUにアクセスするため、第2回で設定したNVIDIA Container Toolkitが必要です。

cat << 'EOF' | sudo tee /etc/containers/systemd/dcgm-exporter.container
[Unit]
Description=NVIDIA DCGM Exporter
After=network-online.target

[Container]
Image=nvcr.io/nvidia/k8s/dcgm-exporter:latest
ContainerName=dcgm-exporter
# 全てのGPUをパススルー
AddDevice=nvidia.com/gpu=all
# Linuxのプロセス情報(PID等)を取得するための権限設定
SecurityLabelDisable=true
Volume=/proc:/host/proc:ro
# DCGMのデフォルトポート9400をホストのネットワークで公開
Network=host

[Install]
WantedBy=multi-user.target
EOF

これらのエクスポーターを systemctl daemon-reload して起動し、ブラウザやcurlで http://<サーバーIP>:9100/metrics(Node-Exporter)および http://<サーバーIP>:9400/metrics(DCGM-Exporter)にアクセスし、膨大なテキストデータが出力されれば成功です。

3. Prometheusによるメトリクス収集(Pullアーキテクチャ)の構築

次に、先ほど立ち上げた各種エクスポーター、およびvLLMやQdrant自身が公開しているメトリクスエンドポイントから定期的にデータを「Pull(取得)」し、時系列データベースとして保存するPrometheus(プロメテウス)を構築します。

3.1. Prometheus設定ファイル(prometheus.yml)の作成

Prometheusがどこにデータを取りに行くかを定義するスクレイプ設定ファイルを作成します。今回は監視対象がすべて同じホスト(あるいは同一ネットワーク内)で稼働している前提です。

# 設定ファイル格納用ディレクトリ
sudo mkdir -p /etc/prometheus

cat << 'EOF' | sudo tee /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s      # 15秒間隔でメトリクスを収集
  evaluation_interval: 15s

scrape_configs:
  # 1. Prometheus自身の監視
  - job_name: 'prometheus'
    static_configs:
      - targets: ['127.0.0.1:9090']

  # 2. OSレイヤーの監視 (Node-Exporter)
  - job_name: 'node'
    static_configs:
      - targets: ['127.0.0.1:9100']

  # 3. GPUハードウェアの監視 (DCGM-Exporter)
  - job_name: 'gpu'
    static_configs:
      - targets: ['127.0.0.1:9400']

  # 4. LLM推論エンジン (vLLM)
  - job_name: 'vllm'
    static_configs:
      - targets: ['127.0.0.1:8000']

  # 5. ベクトルデータベース (Qdrant)
  - job_name: 'qdrant'
    static_configs:
      - targets: ['127.0.0.1:6333']
EOF

⚠️ メトリクスの保持期間とストレージ設計
Prometheusは時系列データをローカルディスクに保存します。デフォルトの保持期間は15日ですが、AIインフラの長期間のトレンド(例:四半期ごとのAPI利用量の増加傾向)を分析したい場合は、保持期間を延ばす必要があります。ただし、取得対象が多いとディスク消費量が跳ね上がるため、NVMe SSD上に十分な監視用パーティションを確保するインフラ設計が不可欠です。

3.2. Prometheusコンテナのデプロイ

データを永続化するディレクトリを作成し、Quadletユニットを定義して起動します。

sudo mkdir -p /var/lib/prometheus
sudo chown -R 65534:65534 /var/lib/prometheus # nobodyユーザー権限
sudo chcon -Rt svirt_sandbox_file_t /var/lib/prometheus

cat << 'EOF' | sudo tee /etc/containers/systemd/prometheus.container
[Unit]
Description=Prometheus Time Series Database
After=network-online.target

[Container]
Image=quay.io/prometheus/prometheus:latest
ContainerName=prometheus
Network=host
Volume=/etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
Volume=/var/lib/prometheus:/prometheus:rw
# メトリクスの保持期間を30日間に設定
Exec=--config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=30d

[Install]
WantedBy=multi-user.target
EOF

# 起動
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus.service

4. GrafanaによるAIインフラ可視化とPromQLの活用

Prometheusが収集した無数の数値データを、人間が直感的に分析できるグラフィカルなダッシュボードへと変換するのがGrafana(グラファナ)です。

4.1. Grafanaコンテナのデプロイ

sudo mkdir -p /var/lib/grafana
sudo chown -R 472:472 /var/lib/grafana
sudo chcon -Rt svirt_sandbox_file_t /var/lib/grafana

cat << 'EOF' | sudo tee /etc/containers/systemd/grafana.container
[Unit]
Description=Grafana Visualization Server
After=network-online.target

[Container]
Image=docker.io/grafana/grafana:latest
ContainerName=grafana
# 外部公開ポートを3000にバインド(本番ではNginx等の背後に配置)
PublishPort=0.0.0.0:3000:3000
Volume=/var/lib/grafana:/var/lib/grafana:rw

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now grafana.service

ブラウザで http://<サーバーIP>:3000 にアクセスし、初期パスワード(admin/admin)でログイン後、Data Sourcesとして http://127.0.0.1:9090 (Prometheus) を追加します。

PR

4.2. インフラエンジニアが監視すべき「3つの重要指標」とPromQL

Grafanaのダッシュボードにパネルを追加する際、Prometheusのクエリ言語であるPromQLを使用します。AIインフラ管理において、絶対にダッシュボードの中央に配置すべき3つの指標と、そのクエリを解説します。

① vLLMのKVキャッシュ使用率とキューイング状況

「ユーザーが順番待ちをしていないか(レスポンス遅延の直接原因)」を特定するための最も重要な指標です。
vLLMはKVキャッシュ領域の使用率をパーセンテージで出力します。これが1.0(100%)に達すると、新しく来たリクエストは「Pending(待機)」キューに入ります。

# KVキャッシュの使用率(0.0 〜 1.0)
vllm:gpu_cache_usage_perc

# 現在処理待ち(キューに積まれている)のリクエスト数
vllm:num_requests_waiting

もし vllm:num_requests_waiting が恒常的に0より大きい値を示している場合、現在のVRAM容量に対して同時アクセスユーザー数が限界を超えていることを意味します。対策としては、GPUを増設してテンソル並列(Tensor Parallel)を組むか、第5回で解説したコンテキストサイズ(--max-model-len)を削ってKVキャッシュブロックを確保するチューニングが必要です。

② DCGMによる正確なGPU消費電力とサーマルスロットリング

高負荷なバッチ推論が連続すると、GPUは猛烈な熱を発します。温度が規定値(例:85℃)を超えると、GPUは自身の破壊を防ぐために強制的にクロック周波数を落とします(サーマルスロットリング)。これにより、モデルの計算は正常に行われているように見えても、Tokens/secが劇的に低下します。

# GPUの現在の温度(摂氏)
DCGM_FI_DEV_GPU_TEMP

# GPUの消費電力(ワット)
DCGM_FI_DEV_POWER_USAGE

# スロットリングが発生しているかどうかのフラグ(1ならクロックダウン発生中)
DCGM_FI_DEV_THERMAL_VIOLATION

③ トークン生成スループット(Tokens/sec)

AIシステム全体のパフォーマンス(馬力)を測る最終的なKPIです。1秒間にシステム全体で何トークン生成できているかを可視化します。

# 過去1分間の平均トークン生成速度(Tokens per second)
rate(vllm:generation_tokens_total[1m])
コウ君

なるほど!ダッシュボードを見れば、ユーザーから「遅い」と言われたときに、「今KVキャッシュが枯渇して順番待ちになっている」のか、「熱暴走でGPUクロックが下がっている」のか、「単に重い(長い)プロンプトを投げたユーザーがVRAMを占有している」のかが、一目で原因切り分けできるんですね。

5. ローカルLLM環境を守るエンタープライズ・セキュリティ設計

可視化基盤が整い、インフラの安定稼働が担保されました。最後に立ちはだかるのは「セキュリティ」の壁です。社内の機密データ(RAGのベクトルDB)や強力な計算資源(GPU)に対する不正アクセスを防ぐための、インフラエンジニアによる防衛線の構築です。

5.1. AIインフラ特有の脆弱性とリスク

ローカルLLMアーキテクチャでは、多数のマイクロサービス(vLLM, TEI, Qdrant)がHTTP/RESTやgRPCを用いて通信します。これらはデフォルトでは「暗号化なしの平文通信」であり、「認証機能を持たない」ことがほとんどです。

もしサーバーのポートが社内ネットワーク(あるいはインターネット)に直接開放されていた場合、悪意のある内部犯やマルウェアによって以下の被害が発生します。

  • プロンプト・インジェクションの踏み台: 認証なしのAPIを叩かれ、社内システムに対する攻撃コードを生成させられる。
  • 機密データの流出: Qdrantのポート(6333)に直接アクセスされ、社内の全PDFドキュメントのベクトルデータとペイロード(本文)を抜き取られる。
  • リソース・ハイジャック(GPUマイニング): GPUの計算資源を乗っ取られ、仮想通貨のマイニング等に不正利用される。

5.2. ネットワークセグメンテーションとFirewalldの厳格化

これを防ぐための第一原則が「ゼロトラスト(何も信頼しない)」に基づくネットワークセグメンテーションです。
AlmaLinux標準の firewalld を用いて、ホスト外部からの直接アクセスを完全に遮断し、フロントエンドのNginx(またはAPI Gateway)からの通信のみを許可する堅牢な壁を構築します。

# firewalldが稼働していることを確認
sudo systemctl status firewalld

# まずは全てのポート(SSHとHTTPS以外)がパブリックゾーンから閉じられているか確認
sudo firewall-cmd --list-all

# 万が一、vLLM(8000)やQdrant(6333), Grafana(3000)が外部公開されている場合は削除
# sudo firewall-cmd --remove-port=8000/tcp --permanent

# 必要な通信(例:HTTPS)のみを明示的に許可
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

本連載のQuadlet設定では、PublishPort=127.0.0.1:8000:8000 のように、あえて 127.0.0.1(ローカルループバック)にバインドするように記述してきました。これは、ホスト内(Nginxや同居するコンテナ間)でのみ通信を許可し、外部の物理NICからはアクセスさせないための重要なインフラ・セキュリティ設計です。

5.3. TLS暗号化、OAuth2 Proxyによる認証インテグレーション

全てのトラフィックの入り口となるNginxにおいて、TLS(SSL)による通信の暗号化を必須とします。
さらに、エンタープライズ環境では単なるBasic認証ではなく、社内のActive Directory (AD) や Microsoft Entra ID (旧Azure AD)、OktaなどのIDプロバイダと連携したSSO(シングルサインオン)が求められます。

インフラエンジニアとしては、アプリケーション側に認証ロジックを実装させるのではなく、Nginxの背後に 「OAuth2 Proxy」 コンテナを配置し、インフラレイヤーで認証・認可を強制ブロックするアーキテクチャ(Identity-Aware Proxy)を構築するのが現代のベストプラクティスです。これにより、AIコンポーネント(GrafanaダッシュボードやvLLMのAPI)自体に認証機能がなくても、認証を通過した正当な社内ユーザーしか到達できないセキュアな閉域空間が完成します。

⚠️ 監査ログ(Audit Logging)の保全
「誰が、いつ、どのようなプロンプトをAIに投げ、どのようなドキュメントが検索されたか」のログは、情報漏洩やコンプライアンス違反時のフォレンジック(原因究明)において決定的な証拠となります。NginxのアクセスログやvLLMのコンテナログをローカルに放置せず、FluentdやRsyslogを用いて社内の安全な統合ログ管理サーバー(SIEM等)へリアルタイムに転送(退避)するインフラパイプラインを必ず構築してください。

6. まとめと次回の予告

本記事「【第7回】ローカルLLM環境の監視(Prometheus/Grafana)とセキュリティ設計」では、PoCレベルのAI環境をエンタープライズの本番インフラへと昇華させるための、以下の重要な設計・実装を行いました。

  • ブラックボックス化の解消: 従来のOS監視に加え、LLM特有のKVキャッシュ枯渇やサーマルスロットリングといった障害要因を特定する必要性を学んだ。
  • DCGMとPrometheus基盤: NVIDIA DCGM-ExporterとNode-Exporterをデプロイし、PrometheusによるPull型の時系列メトリクス収集基盤をQuadletで構築した。
  • Grafanaによるインサイトの可視化: PromQLを駆使し、VRAMのフラグメンテーション、GPUの熱・電力状態、そしてトークン生成スループットをリアルタイムに把握するダッシュボード設計を解説した。
  • ゼロトラスト・セキュリティ: コンテナネットワークのローカルバインド、Firewalldによるアクセス遮断、そしてOAuth2 Proxy連携によるAPI保護という多層防御アーキテクチャを確立した。

これで、AIの「構築(第1〜6回)」「監視(第7回)」「保護(第7回)」というインフラライフサイクルの全てが網羅されました。
次回はついに連載の最終回。【第8回】エンタープライズ向け運用ベストプラクティスとトラブルシューティングです。長期間の運用で直面するであろう「モデルの無停止アップデート戦略(Blue-Greenデプロイメント)」「RAGのベクトルDBバックアップ設計」、そして「VRAMリーク時の緊急対応フロー」など、現場のインフラエンジニアが生き残るための実践的なナレッジの総決算をお届けします。ご期待ください!

▼ 【セキュアなAIインフラ環境を構築しよう】 ▼

強固なセキュリティと専有リソース
「高コスパおすすめVPS・専用サーバー」

VPSランキングを見る

監視・保守のスペシャリストを目指す
「インフラエンジニア専門転職」

転職エージェントを見る

コメント