LabHub

ブログ

Kubernetes HPA・VPA・KEDAオートスケーリング本番運用

한국어English日本語

Kubernetes HPA VPA KEDA Autoscaling Production

はじめに

プロダクションのKubernetesクラスタにおいて、オートスケーリングは選択ではなく必須だ。トラフィック急増時にPodが不足すればサービス障害につながり、過剰プロビジョニングは毎月数百万ウォンの不要なクラウドコストを発生させる。Kubernetesエコシステムは、この問題を解決するために3つの中核的なオートスケーラーを提供している。

本記事では、各オートスケーラーのアーキテクチャとプロダクション環境における踏み込んだ構成戦略を扱い、実際の障害事例と復旧手順、そしてプロダクション投入前に必ず確認すべきチェックリストまで総合的に整理する。

HPA v2の詳細分析

アーキテクチャとメトリクス収集の流れ

HPA v2(autoscaling/v2)はKubernetesの標準的な水平拡張メカニズムだ。HPAコントローラーはデフォルトで15秒周期(--horizontal-pod-autoscaler-sync-period)でメトリクスを収集し、目標使用率と現在の使用率の比率を計算してレプリカ数を決定する。

メトリクス収集の流れは次のとおりだ。

  1. Metrics Server: kubeletのcAdvisorからCPU/メモリのメトリクスを収集し、metrics.k8s.io APIとして公開
  2. Custom Metrics Adapter: Prometheus、Datadogなどからカスタムメトリクスを custom.metrics.k8s.io APIとして公開
  3. External Metrics Adapter: クラスタ外部システムのメトリクスを external.metrics.k8s.io APIとして公開

スケーリングアルゴリズム

HPAの中核となる計算式は次のとおりだ。

desiredReplicas = ceil(currentReplicas * (currentMetricValue / desiredMetricValue))

例えば、現在3個のPodがCPUを80%使用していて目標が50%であれば、ceil(3 * (80/50)) = ceil(4.8) = 5個に拡張される。複数のメトリクスが指定されている場合、HPAは各メトリクスについて独立に計算したうえで もっとも大きい値 を採用する。

プロダクション向けHPA v2マニフェスト

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 70
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: '1000'
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
        - type: Pods
          value: 5
          periodSeconds: 60
      selectPolicy: Max
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 10
          periodSeconds: 120
      selectPolicy: Min

重要なポイントは behavior フィールドだ。

Metrics Serverのインストール確認

# Metrics Serverの動作確認
kubectl top nodes
kubectl top pods -n production

# HPAの状態確認
kubectl get hpa api-server-hpa -n production -o yaml

# HPAのイベント確認
kubectl describe hpa api-server-hpa -n production | grep -A 20 "Events"

kubectl top nodes が失敗する場合は、Metrics Serverがインストールされていないか正常に動作していない。この場合HPAはメトリクスを収集できず、スケーリングがまったく動作しない。

VPAのアーキテクチャと運用戦略

VPAの構成要素

VPAは3つの主要コンポーネントで構成される。

  1. Recommender: 過去のリソース使用量とOOMイベントを分析し、最適なCPU/メモリの要求値を計算する。ヒストグラムベースのアルゴリズムで、P95使用量を基準に推奨値を導き出す。
  2. Updater: 現在のPodのリソース設定が推奨値から大きく外れると、Podを退去(eviction)させて新しい推奨値が適用されるようにする。
  3. Admission Controller: 新しく作成された、または再起動されたPodに推奨リソース値を自動的に適用するWebhookだ。

運用モード

VPAは4つの updateMode をサポートする。

プロダクション向けVPAマニフェスト

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-server-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: 'Off'
  resourcePolicy:
    containerPolicies:
      - containerName: api-server
        minAllowed:
          cpu: '100m'
          memory: '128Mi'
        maxAllowed:
          cpu: '4'
          memory: '8Gi'
        controlledResources:
          - cpu
          - memory
        controlledValues: RequestsAndLimits

プロダクション環境では必ず Offモードで開始 し、最低1-2週間にわたって推奨値の安定性を観察したうえで、AutoまたはRecreateモードへ切り替える必要がある。minAllowedmaxAllowed を必ず設定し、異常な推奨値が適用されるのを防ぐ。

VPAの推奨値の確認

# VPAの推奨値を確認
kubectl describe vpa api-server-vpa -n production

# 推奨値と現在のリソース要求値を比較
kubectl get vpa api-server-vpa -n production -o jsonpath='{.status.recommendation.containerRecommendations[0]}'

KEDAによるイベント駆動スケーリング

KEDAのアーキテクチャ

KEDAはKubernetesのHPAを拡張し、外部イベントソースをもとにスケーリングを可能にするCNCF Graduatedプロジェクトだ。KEDAの中核コンポーネントは次のとおりだ。

  1. KEDA Operator: ScaledObject/ScaledJob CRDを監視し、HPAを自動生成/管理する。イベントがないときはPodを0に縮小し、イベント発生時に1へ活性化したうえでHPAへ制御を渡す。
  2. Metrics Server (KEDA): 外部イベントソースのメトリクスをKubernetes External Metrics APIとして公開する。
  3. Scalers: 65種類以上のイベントソース(Kafka、RabbitMQ、AWS SQS、Prometheus、PostgreSQL、Cronなど)に接続するアダプタだ。

スケーリングの流れ

KEDAのスケーリングは2段階で動作する。

  1. Activation段階: KEDA Operatorがイベントソースを監視し、トリガー条件が満たされるとDeploymentのレプリカを0から1へ活性化する。
  2. Scaling段階: 活性化された後は、KEDAが作成したHPAがメトリクスをもとに1からNまでの拡張/縮小を担当する。

KEDA ScaledObjectマニフェスト

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: order-processor-scaledobject
  namespace: production
spec:
  scaleTargetRef:
    name: order-processor
  pollingInterval: 15
  cooldownPeriod: 300
  idleReplicaCount: 0
  minReplicaCount: 1
  maxReplicaCount: 100
  fallback:
    failureThreshold: 3
    replicas: 5
  triggers:
    - type: kafka
      metadata:
        bootstrapServers: kafka-broker:9092
        consumerGroup: order-processor-group
        topic: orders
        lagThreshold: '50'
    - type: prometheus
      metadata:
        serverAddress: http://prometheus:9090
        metricName: http_requests_total
        query: sum(rate(http_requests_total[2m]))
        threshold: '100'

中核となる構成要素を見ていくと、次のとおりだ。

KEDAのインストールと確認

# HelmでKEDAをインストール
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --namespace keda --create-namespace

# KEDAの状態確認
kubectl get pods -n keda
kubectl get scaledobjects -n production
kubectl get hpa -n production

# ScaledObjectの詳細確認
kubectl describe scaledobject order-processor-scaledobject -n production

HPA・VPA・KEDAの比較分析

項目HPAVPAKEDA
スケーリング方向水平 (Pod数の増減)垂直 (リソース要求/制限の調整)水平 (イベント駆動でのPod数の増減)
標準メトリクスCPU、メモリCPU、メモリの使用履歴外部イベントソース (65+スケーラー)
カスタムメトリクスサポート (Adapterが必要)非サポート組み込みでサポート
Scale-to-Zero非サポート (minReplicasは1以上)該当なしサポート
Podの再起動不要必要 (Recreateモード)不要
適したワークロードステートレスなWebサービス、APIすべてのワークロード (リソース最適化)イベント駆動、バッチ処理、キュー処理
Kubernetes組み込みはい別途インストールが必要別途インストールが必要
HPAとの関係-CPU/メモリメトリクスで衝突する可能性HPAを内部的に生成/管理
学習コスト低い中程度中程度〜高い
コスト最適化中程度 (過剰拡張の可能性)高い (right-sizing)高い (Scale-to-Zero)

利用シナリオ別の推奨

複合スケーリングパターン

HPA + VPAの組み合わせ

HPAとVPAを同時に使う際にもっとも重要な原則は、同じメトリクスで衝突させない ことだ。

# HPA: カスタムメトリクス(RPS)のみをもとに水平拡張
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: '500'
---
# VPA: CPU/メモリのみ垂直調整 (HPAはカスタムメトリクスのみ使うため衝突しない)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  updatePolicy:
    updateMode: 'Auto'
  resourcePolicy:
    containerPolicies:
      - containerName: api-server
        controlledResources:
          - cpu
          - memory
        minAllowed:
          cpu: '200m'
          memory: '256Mi'
        maxAllowed:
          cpu: '2'
          memory: '4Gi'

このパターンではHPAがRPS(秒間リクエスト数)だけを基準にPod数を調整し、VPAがCPU/メモリのリソースを最適化する。両者が同じメトリクス(CPU/メモリ)を使うと、HPAがPodを増やして使用率を下げ、VPAがリソースを減らして使用率を再び上げるという 無限ループ(thrashing)が発生する。

HPA + KEDAの組み合わせ

KEDAは内部的にHPAを生成するため、別途HPAを作る必要はない。ただし、複数のイベントソースを1つのScaledObjectにまとめることはできる。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: multi-trigger-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: api-server
  minReplicaCount: 2
  maxReplicaCount: 50
  triggers:
    - type: prometheus
      metadata:
        serverAddress: http://prometheus:9090
        metricName: nginx_connections_active
        query: sum(nginx_ingress_controller_nginx_process_connections)
        threshold: '100'
    - type: cron
      metadata:
        timezone: Asia/Seoul
        start: 30 8 * * 1-5
        end: 30 18 * * 1-5
        desiredReplicas: '10'

この例は、Prometheusメトリクスにもとづく動的スケーリングと、Cronにもとづく予約スケーリングを組み合わせている。平日の午前8時30分から午後6時30分までは最低10個のPodを維持しつつ、同時にアクティブな接続数に応じて追加の拡張ができる。

運用時の注意点

1. フラッピング(Flapping)の防止

HPAが頻繁にスケールアップ/ダウンを繰り返す現象をフラッピングと呼ぶ。これを防ぐには次を確認する。

2. リソース制限(Limits)の設定漏れ

PodにCPU/メモリのlimitsが設定されていないと、HPAのパーセントベースのスケーリングが動作しない。必ず resources.requests を設定しなければならない。

resources:
  requests:
    cpu: '500m'
    memory: '512Mi'
  limits:
    cpu: '1000m'
    memory: '1Gi'

3. メトリクスの遅延(Lag)

Metrics Serverには約15秒の遅延があり、Prometheusベースのカスタムメトリクスはscrape intervalとadapterの処理時間まで合わせると30-60秒の遅延が発生しうる。トラフィック急増時にはこの遅延の間、既存のPodに過負荷がかかりうるため、次を検討する。

4. VPAとHPAを同時に使う際の衝突

VPAが Auto または Recreate モードで、かつHPAがCPU/メモリのメトリクスを使うと、両者が互いに相反する判断を下す。必ず次のいずれかを選ぶ。

5. Cluster Autoscalerとの連携

HPAがPod数を増やしても、クラスタに利用可能なノードがなければPodはPending状態のままになる。Cluster Autoscaler(またはKarpenter)が連携されていて初めて、ノードレベルの拡張が行われる。

障害事例と復旧手順

事例1: Metrics Serverの障害によるHPAの無力化

症状: すべてのHPAの TARGETS 列に unknown が表示され、Pod数が固定される。

# 診断
kubectl get hpa -A
kubectl top nodes  # 失敗する場合はMetrics Serverの問題

# Metrics Serverの状態確認
kubectl get pods -n kube-system | grep metrics-server
kubectl logs -n kube-system deployment/metrics-server --tail=50

復旧手順:

  1. Metrics Server Podの再起動: kubectl rollout restart deployment/metrics-server -n kube-system
  2. APIServiceの登録確認: kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
  3. 問題が継続して発生する場合はMetrics Serverを再インストール
  4. 復旧するまで手動でレプリカ数を調整: kubectl scale deployment/api-server --replicas=10 -n production

事例2: OOM Killの連鎖発生

症状: VPAの推奨値が実際のピーク使用量より低く設定され、Podが繰り返しOOMKilledされる。

# OOMイベントの確認
kubectl get events -n production --field-selector reason=OOMKilling --sort-by='.lastTimestamp'

# Podの再起動回数の確認
kubectl get pods -n production -o custom-columns=NAME:.metadata.name,RESTARTS:.status.containerStatuses[0].restartCount

復旧手順:

  1. VPAの updateMode を直ちに Off へ変更し、以降のPod変更を防止
  2. 影響を受けるDeploymentのメモリ要求/制限を手動で引き上げ
  3. VPAの maxAllowed の値が実際のピーク使用量を十分にカバーしているか確認
  4. 最低2週間 Off モードで推奨値の安定性を再観察

事例3: スケーリングストーム(Scaling Storm)

症状: HPAが急速に拡張した直後に縮小を繰り返し、Podが生成/削除され続ける。

# HPAのイベントで頻発するSuccessfulRescaleを確認
kubectl describe hpa api-server-hpa -n production | grep SuccessfulRescale

復旧手順:

  1. behavior.scaleDown.stabilizationWindowSeconds を600秒以上に増加
  2. scaleDown.policies の縮小比率を5%以下に制限
  3. メトリクスソースの変動性を分析し、適切な平滑化(smoothing)を適用
  4. 必要に応じてHPAを一時的に無効化し、手動管理へ切り替え

事例4: KEDAのメトリクス収集失敗

症状: ScaledObjectの状態が Unknown で、連携しているHPAのメトリクスが収集されない。

# ScaledObjectの状態確認
kubectl get scaledobject -n production
kubectl describe scaledobject order-processor-scaledobject -n production

# KEDA Operatorのログ確認
kubectl logs -n keda deployment/keda-operator --tail=100 | grep -i error

復旧手順:

  1. イベントソース(Kafka、Prometheusなど)の接続状態を確認
  2. ScaledObjectに fallback 設定があるか確認。なければ追加し、メトリクス失敗時に安全なレプリカ数を維持
  3. KEDA Operatorの再起動: kubectl rollout restart deployment/keda-operator -n keda
  4. 認証情報(TriggerAuthentication)が期限切れになっていないか確認

プロダクションチェックリスト

デプロイ前に次の項目を必ず確認する。

HPA関連:

VPA関連:

KEDA関連:

共通:

参考資料

おわりに

Kubernetesのオートスケーリングは、単にHPAを1つデプロイすれば終わりというものではない。プロダクション環境では、メトリクス収集の安定性、スケーリングアルゴリズムの理解、Cooldown戦略、障害時の復旧手順まで総合的に設計する必要がある。

中核となる原則を整理すると次のとおりだ。

  1. 単一のオートスケーラーに依存するな: HPA、VPA、KEDAにはそれぞれ強みがある。ワークロードの特性に合わせて組み合わせよ。
  2. 縮小は保守的に: スケールアップは速く、スケールダウンはゆっくり。トラフィックの再増加に備える必要がある。
  3. メトリクス障害に備えよ: Metrics Server、Prometheus、外部イベントソースのいずれも障害が起こりうる。Fallback戦略を必ず構成せよ。
  4. まず観察、自動化は後から: VPAはOffモードで開始し、HPAのbehaviorを保守的に設定したうえで、段階的に自動化のレベルを引き上げよ。
  5. モニタリングと通知は基本だ: オートスケーリングの判断過程をGrafanaダッシュボードで可視化し、異常なスケーリングパターンに対する通知を設定せよ。

オートスケーリングを正しく構築すれば、トラフィックが急増しても安定してサービスを提供しながら、クラウドコストを30-50%削減できる。本記事で扱ったパターンとチェックリストが、プロダクション環境におけるオートスケーリング戦略の策定に実質的な助けとなれば幸いだ。

コメント

まだコメントはありません。

ログインするとコメントできます