導入部
ITソリューション企業の技術ディレクターとして、システム受託開発やAI導入コンサルティングの現場から、日々変化する推論ワークロードと格闘している皆さんに、少しでも役立つ知見を共有できればと思います。
「GPUインスタンスを並べているのに、スパイク時に推論遅延が発生する」「夜間のアイドルタイムに無駄なコストがかかり続けている」。実務の現場では、こうした課題に直面するケースが非常に増えています。
Kubernetesはコンテナオーケストレーションの事実上の標準ですが、デフォルトのオートスケーリング設定(HPA)は、Webアプリケーションのような「ステートレスで軽量な」ワークロードを想定して設計されています。しかし、実務で扱うAIモデル、特にLLM(大規模言語モデル)や画像生成モデルは、起動に数分かかり、VRAMを大量に消費し、リクエストごとの処理時間も長いという、全く異なる特性を持っています。
このギャップを埋めるためには、マニフェストファイルのAPIパラメータを、AIワークロードに合わせて精密に調整する必要があります。本記事では、一般的な入門書には書かれていない、AI推論に特化したKubernetesオートスケーリングの最適化設定を、APIリファレンス形式で深掘りしていきます。
1. AI推論オートスケーリングAPIの概要とアーキテクチャ
まずは、なぜ標準の設定ではうまくいかないのか、その技術的な背景と、それを解決するためのアーキテクチャ全体像を整理しましょう。
CPU使用率によるスケーリングの限界
従来のWebサービスでは、CPU使用率がトラフィックと綺麗に比例することが多いため、targetCPUUtilizationPercentageを設定するだけで事足りました。しかし、AI推論においては以下の理由からCPU指標は役に立たないことが多いのです。
- GPU律速: 推論処理のボトルネックはGPU演算やメモリ帯域にあり、CPUは遊んでいる(アイドル状態)ケースが多いのが実情です。
- 非線形な負荷: バッチ処理や特定の入力トークン長によって、リソース消費が急激に跳ね上がることがあります。
- モデルロードの遅延: Podが起動しても、数GB〜数十GBのモデルデータをGPUメモリにロードするまではリクエストを処理できない(Ready状態にならない)という特性があります。
このため、単にCPU負荷を見てPodを増やしても、「処理できないPodが増えるだけ」で、逆にクラスタ全体のパフォーマンスを落とすことさえあります。
autoscaling/v2 (HPA) と KEDA Custom Resource の関係
そこで必要になるのが、より高度な指標(メトリクス)に基づいたスケーリングです。現代のAI基盤では、以下の2つのAPIリソースを組み合わせて使用するのがベストプラクティスです。
HorizontalPodAutoscaler (HPA) v2:
Kubernetesの標準APIであるautoscaling/v2を使用します(古いv2beta系は廃止されているため注意が必要です)。HPAはスケーリングの計算ロジックや、スケールアップ・ダウンの速度制御(Stabilization Window)を担当します。最新のKubernetes環境ではAIベースのリソース最適化機能なども議論されていますが、プロダクション環境での確実な運用には、依然としてHPA v2の適切な設定が不可欠です。KEDA (Kubernetes Event-driven Autoscaling):
イベント駆動スケーリングのための拡張ツールです。Prometheusのメトリクスに加え、各種クラウドサービスのイベントソースを監視し、HPAに対して「今、これだけのレプリカ数が必要だ」という情報を渡す役割(External Metrics Server)を果たします。- AWS環境での活用: 従来からのAWS SQS(キュー長)監視に加え、最新の環境ではAmazon CloudWatchの拡張メトリクスや、AWS IoT Coreなどのイベントソースをトリガーとして活用するケースも増えています。利用可能なスケーラーや連携機能は常にアップデートされているため、公式ドキュメントで最新の対応状況を確認することをお勧めします。
推論ワークロード向けAPI階層図
AI推論のためのスケーリングスタックは、以下のような階層構造になっています。
- Layer 1: Metrics Source (Prometheus, CloudWatch等)
- GPU使用率、推論キューの滞留数、レイテンシなどを収集。
- Layer 2: KEDA ScaledObject
- メトリクスを監視し、スケーリングのトリガーを定義。
- HPAリソースを自動生成・管理。
- Layer 3: HPA Controller
- KEDAから渡された推奨レプリカ数と、自身の設定(behavior)に基づき、最終的なPod数を決定。
- Layer 4: Deployment / StatefulSet
- 実際にPodの増減を行う。
この構造を理解した上で、各レイヤーのパラメータをどう設定すべきか、具体的に見ていきましょう。
2. HPA (autoscaling/v2) API仕様とAI向け最適化設定
KEDAを使用する場合でも、裏側で動いているのはHPAです。特にautoscaling/v2 APIで導入されたbehaviorセクションは、AIモデルの特性に合わせたチューニングにおいて極めて重要です。
behaviorフィールドによるスケーリング速度の制御
AIモデルは「重い」ため、頻繁なスケールアップ・ダウン(フラッピング)は致命的です。特にスケールダウンが早すぎると、直後にトラフィックが戻った際に、再度モデルロードの長い待ち時間が発生してしまいます。
以下は、AI推論向けに最適化したHPA設定の例です。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-inference-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-inference-deployment
minReplicas: 1
maxReplicas: 10
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 重要ポイント1
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Pods
value: 2
periodSeconds: 15
- type: Percent
value: 100
periodSeconds: 15
selectPolicy: Max # 重要ポイント2
stabilizationWindowSecondsによるフラッピング防止
重要ポイント1: scaleDown.stabilizationWindowSeconds: 300
この設定は、「負荷が下がってから実際にPodを減らすまでの待機時間」を定義します。デフォルトは300秒(5分)ですが、モデルのロード時間が長い場合や、トラフィックの波が荒い場合は、これを600秒(10分)やそれ以上に伸ばすことを検討してください。
これにより、一時的なトラフィックの谷間でPodが削除され、直後の山で「Pod起動待ち」によるレイテンシ悪化が発生するのを防げます。コスト削減よりもユーザー体験(低遅延)を優先する場合の必須設定です。
selectPolicy: Min/Max/Disabled の使い分け
重要ポイント2: scaleUp.selectPolicy: Max
急激なトラフィック増(スパイク)に対応するためには、スケールアップのポリシーを複数定義し、その中で「最も多くのPodを追加するポリシー」を採用するように設定します。
上記の例では、「一度に2つのPodを追加する」か「現在のPod数を倍(100%増)にする」かのうち、大きい方を採用します。これにより、低負荷時は緩やかに、高負荷時はアグレッシブにスケールするという挙動を実現できます。AI推論のような、リクエストが突発的に集中しやすいワークロードに適しています。
3. KEDA ScaledObject API仕様詳解
KEDAを利用することで、より柔軟な「イベント駆動」のスケーリングが可能になります。ここではScaledObjectリソースの重要なパラメータを解説します。
PollingIntervalとCooldownPeriodの設定戦略
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: ai-inference-scaledobject
spec:
scaleTargetRef:
name: ai-inference-deployment
pollingInterval: 15 # メトリクス確認間隔(秒)
cooldownPeriod: 300 # 0レプリカに戻るまでの待機時間(秒)
minReplicaCount: 1 # 最小レプリカ数
maxReplicaCount: 10 # 最大レプリカ数
pollingInterval: KEDAがメトリクスソース(Prometheus等)を確認しに行く頻度です。デフォルトは30秒ですが、リアルタイム性が求められる推論APIでは15秒程度に短縮することを推奨します。これ以上短くしても、Prometheus側のスクレイピング間隔(通常15秒〜1分)がボトルネックになるため意味がありません。
cooldownPeriod: 最後のイベントが発生してから、レプリカ数を0(ゼロスケール有効時)に戻すまでの待機時間です。これはHPAの
stabilizationWindowSecondsとは別に、KEDAが独自に管理するタイマーです。
minReplicaCount: 0 (Zero-scale) のメリットとリスク
KEDAの最大の特徴は、minReplicaCount: 0を設定することで、リクエストがない時にPod数を0にし、完全にコストをカットできる点です(Scale to Zero)。
しかし、AI推論においてはこの設定は慎重に行うべきです。費用対効果を重視する観点からも、以下のメリットとリスクを天秤にかける必要があります。
- メリット: 夜間や休日など、全く使われない時間帯のGPUコストをゼロにできる。
- リスク(コールドスタート): 最初のリクエストが来てからPodが起動し、モデルをロードして応答可能になるまで、数分待たされることになります。ユーザー向けのリアルタイム機能では許容されない遅延です。
推奨設定:
- 社内ツールやバッチ処理:
minReplicaCount: 0でコスト削減を最大化。 - 本番ユーザー向けAPI:
minReplicaCount: 1以上を維持し、即応性を確保。
advanced: horizontalPodAutoscalerConfig の活用
KEDAが生成するHPAの挙動を微調整したい場合、advancedセクションを使用します。前述のHPA behavior設定をKEDA経由で適用するには以下のように記述します。
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 600
これにより、KEDAの便利さとHPAの詳細制御を両立させることができます。
4. トリガー設定リファレンス:Prometheus & GPU Metrics
「何を基準にスケールするか」が、オートスケーリングの成否を分けます。AI推論で最も信頼性が高いのは、GPU使用率ではなく、リクエストの滞留状況です。
triggers.metadata.query の記述ベストプラクティス
Prometheusをソースとする場合のScaledObject設定例です。
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-server.monitoring.svc.cluster.local
metricName: inference_queue_depth
threshold: '5' # 目標とする1Podあたりのキュー滞留数
query: |
sum(inference_server_queue_size{model_name="gpt-j"})
threshold 値の算出ロジック(リクエスト単価計算)
thresholdの設定値は、「1つのPodが許容できる負荷の限界」ではなく、「スケールアウトを開始させたい目標値」であることに注意してください。
例えば、1リクエストの処理に平均200msかかるとします。
SLA(サービスレベル合意)として、「待ち時間を1秒以内に抑えたい」場合、許容できるキューの長さ(Queue Depth)は以下のように計算できます。
$$ \text{許容Queue Depth} = \frac{\text{目標待ち時間 (1000ms)}}{\text{処理時間 (200ms)}} = 5 $$
つまり、キューに5個リクエストが溜まった時点で、次のPodが必要になるということです。この値をthresholdに設定します。
GPU使用率 vs キュー滞留数(Queue Depth)
なぜGPU使用率(DCGM Exporterなどのメトリクス)をトリガーにしないのでしょうか?
メモリ割り当てとキャッシュの挙動: PyTorchやTensorFlowなどの主要フレームワークは、推論速度を優先して起動時にVRAMを積極的に確保(キャッシュ)する仕様が一般的です。
- 最新の推論環境(例えばNVIDIAのNVFP4/NVFP8技術や最新のCUDAバージョンなど)ではVRAM効率が劇的に改善されていますが、「確保済みメモリ(Reserved)」と「実使用メモリ(Allocated)」の乖離が発生しやすい特性は変わりません。
- そのため、Kubernetes上では実際には処理していなくてもメモリ使用率が高止まりして見えることが多く、負荷の指標としては不正確になりがちです。
感度の問題: GPU演算コアの使用率(SM Utilization)は、バッチサイズやモデル構造によって変動が激しく、リクエスト数と綺麗に比例しないことがあります。
対して、キュー滞留数(Queue Depth)や進行中のリクエスト数(In-flight Requests)は、ユーザー体験(遅延)に直結する指標です。「処理待ちが増えたらスケールする」というロジックの方が、AI推論においては確実性が高いのです。
5. トラブルシューティングとAPIステータス確認
設定を投入しても、期待通りにスケールしないことはよくあります。そんな時は、APIリソースのstatusフィールドを確認するのが近道です。
ReadyConditionとActiveConditionの読み方
kubectl describe scaledobject <name>を実行すると、下部にStatusが表示されます。
- Ready: KEDAが外部メトリクスソース(PrometheusやAWS CloudWatch等)に正常に接続できているかを示します。ここが
Falseの場合、認証情報やURL、クエリ構文に誤りがあります。 - Active: 現在のスケーリング状態を示します。
Trueであれば、閾値を超過し、スケールアウト(0から1以上へ)がトリガーされたことを意味します。
HPA計算不能時のフォールバック動作
Prometheusがダウンした場合など、メトリクスが取得できなくなった際の安全策として、fallback設定を入れておくことを強くお勧めします。
fallback:
failureThreshold: 3
replicas: 5
この設定により、メトリクス取得エラーが3回続いた場合、強制的にレプリカ数を5に固定します。これにより、監視システムの障害がサービスダウン(Pod数0や不足)に繋がる最悪の事態を回避できます。
よくある設定ミス
- 認証エラー: クラウドプロバイダー(AWS/GCP/Azure)のマネージドサービスを使用する場合、KEDAに適切なIAMロールや認証設定(TriggerAuthentication)を紐付けるのを忘れがちです。特にAWS環境では、IAMポリシーの変更やローテーションが見落とされるケースがあります。
- メトリクス遅延: Prometheusのスクレイピング間隔が長いと、スパイク検知が遅れます。ServiceMonitorの設定も見直しましょう。また、AWS CloudWatchなどの外部メトリクスを利用する場合、APIのレート制限やデータ反映のラグが影響することもあります。
- バージョンの不整合: Kubernetesのエコシステムは進化が速く、GKEやEKSなどのマネージドサービスでは定期的なバージョンアップが行われます。新しいバージョンでは、APIの仕様変更や廃止が含まれる場合があります。クラスタのアップグレード後に
autoscaling/v2などのAPIバージョンが適合しなくなるケースがあるため、公式ドキュメントで互換性を確認することが重要です。特に2026年時点の最新環境においては、非推奨APIの削除に注意が必要です。
6. まとめ:実践への次のステップ
ここまで、AI推論ワークロードに特化したKubernetesオートスケーリングのAPI設定について、実務の観点から深掘りして解説してきました。
要点を振り返りましょう。
- HPA behavior:
scaleDownの待機時間を長く設定し、モデルロードのオーバーヘッドによる機会損失を防ぐ。 - KEDA: ポーリング間隔を短くし、即応性を高める。ゼロスケールは用途に応じて慎重に。
- トリガー: GPU使用率ではなく、ビジネスKPIに直結する「キュー滞留数」や「レイテンシ」を基準にする。
これらの設定を適切に組み合わせることで、費用対効果を最大化しつつ、ユーザー体験を損なわない堅牢な推論基盤を構築できます。
実際の現場では「自社のモデルだと具体的にどの値が最適なのか?」「既存のインフラ構成にどう組み込めばいいのか?」といった個別の課題が出てくるものです。推論基盤の最適化は、モデルの特性やビジネス要件によって正解が変わる、非常に奥が深い領域です。
まずは現状のマニフェストとメトリクスを可視化し、ボトルネックを特定するところから始めてみてください。AIインフラの「見えない無駄」をなくし、本来注力すべきモデル開発やサービス改善にリソースを集中させましょう。
コメント