KEDA

KEDA(Kubernetes-based Event Driven Autoscaler)包括的技術ガイド


目次

  1. KEDA とは何か
  2. なぜ KEDA が必要なのか ─ HPA の限界
  3. 主要機能と特徴
  4. HPA / VPA / KEDA の比較
  5. アーキテクチャ詳解
  6. CRD リファレンス
  7. スケーラーカタログ
  8. 高度な機能
  9. インストールと構成
  10. モニタリングとオブザーバビリティ
  11. トラブルシューティング
  12. 実践的ユースケース
  13. セキュリティとベストプラクティス
  14. パフォーマンスチューニング
  15. エコシステムとロードマップ

1. KEDA とは何か

1.1 概要

KEDA(Kubernetes-based Event Driven Autoscaler)は、Kubernetes ワークロードのイベント駆動型オートスケーリングを実現するオープンソースプロジェクトである。Microsoft と Red Hat が共同で開発を開始し、現在は CNCF(Cloud Native Computing Foundation)Graduated プロジェクト として認定されている。これは KEDA が成熟したプロジェクトであり、プロダクション環境での使用に十分な品質を持つことを意味する。

KEDA の核となるコンセプトは 「イベント駆動型のゼロからNへのスケーリング」 である。従来の Kubernetes HPA(Horizontal Pod Autoscaler)が CPU やメモリといったリソースメトリクスに基づいてスケーリングを行うのに対し、KEDA はメッセージキューの深さ、データベースのクエリ結果、HTTP リクエストレート、Cron スケジュールなど、外部イベントソースに基づいてスケーリングを実行する。

1.2 基本的な動作原理

+------------------+     ポーリング      +----------------+
|  外部イベント     |  <------------>  |   KEDA Scaler  |
|  ソース           |                   |                |
|  (Kafka, SQS,    |                   +-------+--------+
|   Prometheus等)  |                           |
+------------------+                           | メトリクス
                                               v
                                    +----------+---------+
                                    | KEDA Metrics       |
                                    | Adapter Server     |
                                    +----------+---------+
                                               |
                                               | External Metrics API
                                               v
                                    +----------+---------+
                                    | Kubernetes HPA     |
                                    | (KEDA が自動管理)   |
                                    +----------+---------+
                                               |
                                               | スケーリング指示
                                               v
                                    +----------+---------+
                                    | Deployment /       |
                                    | StatefulSet /      |
                                    | Custom Resource    |
                                    +--------------------+

KEDA は既存の Kubernetes HPA を置き換えるのではなく、拡張する形で動作する。KEDA は外部メトリクスを Kubernetes の External Metrics API を通じて HPA に提供し、HPA が実際のスケーリング判断を行う。ただし、0→1 および 1→0 のスケーリングは KEDA が直接管理する。

1.3 プロジェクトの歴史と成熟度

時期マイルストーン
2019年5月Microsoft と Red Hat が共同で KEDA を発表
2020年3月CNCF Sandbox プロジェクトとして採択
2021年8月CNCF Incubation プロジェクトに昇格
2023年8月CNCF Graduated プロジェクトに認定
2024年〜v2.x 系の継続的な機能拡張

CNCF Graduated の認定は、セキュリティ監査の通過、安定した API、強固なガバナンス体制、そして広範なプロダクション採用を示す。

1.4 対応する Kubernetes バージョン

KEDA は一般的に、以下の Kubernetes バージョンとの互換性を維持している:

  • KEDA v2.12+ : Kubernetes 1.27 〜 1.29
  • KEDA v2.13+ : Kubernetes 1.28 〜 1.30
  • KEDA v2.14+ : Kubernetes 1.28 〜 1.31

具体的な互換性マトリクスは公式ドキュメントで確認すること。


2. なぜ KEDA が必要なのか ─ HPA の限界

2.1 HPA(Horizontal Pod Autoscaler)の制約

Kubernetes 標準の HPA には、以下の本質的な制約がある:

制約1:メトリクスソースの制限

HPA がネイティブに対応するメトリクスは以下に限定される:

  • CPU 使用率(cpu
  • メモリ使用量(memory
  • カスタムメトリクス(Metrics Adapter が別途必要)
  • 外部メトリクス(External Metrics API 実装が別途必要)

カスタムメトリクスや外部メトリクスを使うには、Prometheus Adapter などのメトリクスアダプターを自前で構築・運用する必要がある。

制約2:ゼロスケーリング不可

HPA の minReplicas の最小値は 1 である。これは、トラフィックが全くない時間帯でも最低1つの Pod を維持する必要があることを意味し、コスト最適化の観点で大きな障壁となる。

# HPA の制約:minReplicas は 1 以上
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 1    # ← ゼロにできない
  maxReplicas: 100
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80

制約3:イベントソース非対応

メッセージキューの未処理メッセージ数、データベースの行数、外部 API のレスポンスなど、ビジネスロジックに直結するメトリクスに基づくスケーリングが困難である。

制約4:複数メトリクスの統合が複雑

HPA v2 は複数メトリクスに対応しているが、各メトリクスの重み付けや複合的な判断ロジックの実装が難しい。

2.2 VPA(Vertical Pod Autoscaler)の役割と限界

VPA はポッドのリソースリクエスト(CPU/メモリ)を自動調整する。スケーリングの方向が「垂直(リソース量の増減)」であるため、HPA の「水平(Pod 数の増減)」とは補完関係にある。ただし、VPA にも以下の制約がある:

  • Pod の再起動が必要(インプレース更新は限定的)
  • HPA との同一メトリクスでの併用が困難
  • イベント駆動型のスケーリングには非対応

2.3 KEDA が解決する課題

KEDA は上記の制約を以下のように解決する:

課題KEDA による解決策
メトリクスソースの制限60以上の組み込みスケーラーを提供
ゼロスケーリング不可0→1、1→0 のスケーリングをネイティブサポート
イベントソース非対応Kafka, SQS, Prometheus 等に直接接続
複合メトリクス複数トリガーと Scaling Modifiers で対応
Adapter の自前構築内蔵の Metrics Adapter Server で不要に

3. 主要機能と特徴

3.1 イベント駆動型スケーリング

KEDA の最大の特徴は、外部イベントソースに基づくスケーリングである。サポートされるイベントソースには以下が含まれる:

  • メッセージキュー: Apache Kafka, AWS SQS, Azure Service Bus, RabbitMQ, NATS, Google Pub/Sub
  • データベース: PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch
  • メトリクス/監視: Prometheus, Datadog, New Relic, Dynatrace, Graphite
  • クラウドサービス: AWS CloudWatch, Azure Monitor, GCP Stackdriver
  • その他: Cron スケジュール, HTTP リクエスト, Kubernetes ワークロード, 外部 API

3.2 ゼロからNへのスケーリング

KEDA の「ゼロスケーリング」機能により、以下のフローが実現する:

イベントなし         イベント検出        負荷増大          負荷減少          イベントなし
    |                    |                |                |                |
    v                    v                v                v                v
 [0 Pods]  ──→  [1 Pod 起動]  ──→  [N Pods]  ──→  [1 Pod]  ──→  [0 Pods]
    │                    │                │                │                │
    │   KEDA Agent が    │  HPA が管理    │  HPA が管理    │  KEDA Agent が │
    │   直接管理         │  (1→N)         │  (N→1)         │  直接管理      │
    │                    │                │                │  (1→0)         │

このフローにより、夜間やトラフィックのない時間帯に Pod 数をゼロにすることで、クラウドコストを大幅に削減できる。

3.3 複数トリガーのサポート

一つの ScaledObject に複数のトリガー(スケーラー)を定義できる。各トリガーが独立にメトリクスを計算し、最も高い値がスケーリングの基準となる(デフォルト動作)。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: multi-trigger-example
spec:
  scaleTargetRef:
    name: my-app
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: my-group
      topic: orders
      lagThreshold: "50"
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      query: rate(http_requests_total{app="my-app"}[2m])
      threshold: "100"
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: "0 9 * * 1-5"
      end: "0 18 * * 1-5"
      desiredReplicas: "3"

3.4 ScaledObject と ScaledJob

KEDA は二つの主要な CRD を提供する:

  • ScaledObject: Deployment, StatefulSet などの長時間実行ワークロードをスケーリング
  • ScaledJob: Kubernetes Job をイベントに応じて作成・スケーリング(バッチ処理に最適)

3.5 認証抽象化

TriggerAuthentication と ClusterTriggerAuthentication CRD により、認証情報をスケーリング定義から分離できる。Kubernetes Secret, HashiCorp Vault, AWS IAM, Azure AD Pod Identity など、複数の認証方式をサポートする。


4. HPA / VPA / KEDA の比較

4.1 機能比較表

機能/特性HPAVPAKEDA
スケーリング方向水平(Pod 数)垂直(リソース量)水平(Pod 数) + Job
メトリクスソースCPU/メモリ/カスタムCPU/メモリ60+ 外部ソース
ゼロスケーリング不可(min=1)不可可能(min=0)
イベント駆動限定的非対応ネイティブ対応
Job スケーリング非対応非対応ScaledJob で対応
複合メトリクス基本的非対応Scaling Modifiers
CRD 必要なし(組み込み)ありあり
CNCF ステータスKubernetes 組み込みSandboxGraduated
スケーリング速度中速低速(再起動)高速(ポーリング間隔)
学習コスト
運用コスト

4.2 使い分けガイドライン

                     ┌────────────────────────────────┐
                     │  ワークロードの特性は?          │
                     └───────────────┬────────────────┘
                                     │
                    ┌────────────────┼────────────────┐
                    │                │                │
                    v                v                v
             CPU/メモリ        イベント駆動      リソース最適化
             ベースの          スケーリング      (Pod サイズ)
             スケーリング       が必要            が必要
                    │                │                │
                    v                v                v
                 ┌──┴──┐       ┌────┴────┐      ┌──┴──┐
                 │ HPA │       │  KEDA   │      │ VPA │
                 └─────┘       └─────────┘      └─────┘
                                     │
                              ┌──────┴──────┐
                              │             │
                              v             v
                       長期実行         バッチ/ジョブ
                       ワークロード     ワークロード
                              │             │
                              v             v
                       ScaledObject    ScaledJob

推奨される組み合わせ:

  1. KEDA + VPA: KEDA でイベント駆動の水平スケーリング、VPA で各 Pod のリソース最適化
  2. HPA + VPA: 標準的なウェブアプリケーション(異なるメトリクスで併用)
  3. KEDA 単独: イベント駆動型マイクロサービス、バッチ処理

注意事項:

  • KEDA と HPA を同じ Deployment に対して同時に使用しないこと(KEDA が内部で HPA を作成するため)
  • VPA と HPA/KEDA を同じメトリクス(CPU/メモリ)で併用しないこと

5. アーキテクチャ詳解

5.1 コンポーネント概要

KEDA は以下の3つの主要コンポーネントで構成される:

┌─────────────────────────────────────────────────────────────────────┐
│                        KEDA System                                  │
│                                                                     │
│  ┌──────────────────────────┐    ┌──────────────────────────────┐  │
│  │   keda-operator          │    │  keda-operator-metrics-      │  │
│  │   (Agent + Controller)   │    │  apiserver                   │  │
│  │                          │    │  (Metrics Adapter Server)    │  │
│  │  ┌────────────────────┐  │    │                              │  │
│  │  │ KEDA Agent         │  │    │  ┌────────────────────────┐  │  │
│  │  │ - 0↔1 スケーリング │  │    │  │ External Metrics API   │  │  │
│  │  │ - ScaledObject 監視│  │    │  │ - HPA へメトリクス提供  │  │  │
│  │  │ - ScaledJob 管理   │  │    │  │ - メトリクスキャッシュ  │  │  │
│  │  └────────────────────┘  │    │  └────────────────────────┘  │  │
│  │                          │    │                              │  │
│  │  ┌────────────────────┐  │    │  ┌────────────────────────┐  │  │
│  │  │ Controller Manager │  │    │  │ Scaler Handler        │  │  │
│  │  │ - CRD の Reconcile │  │    │  │ - メトリクス収集      │  │  │
│  │  │ - HPA 自動生成     │  │    │  │ - スケーラー管理      │  │  │
│  │  │ - リソース管理     │  │    │  │ - ポーリングループ    │  │  │
│  │  └────────────────────┘  │    │  └────────────────────────┘  │  │
│  └──────────────────────────┘    └──────────────────────────────┘  │
│                                                                     │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │                    Scaler Interface                           │  │
│  │  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐│  │
│  │  │Kafka │ │Prom  │ │AWS   │ │Cron  │ │PSQL  │ │External  ││  │
│  │  │Scaler│ │Scaler│ │SQS   │ │Scaler│ │Scaler│ │Scaler    ││  │
│  │  │      │ │      │ │Scaler│ │      │ │      │ │(gRPC)    ││  │
│  │  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────────┘│  │
│  └──────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

5.2 keda-operator(Agent + Controller)

KEDA Agent は以下の責務を持つ:

  1. 0→1 スケーリング: イベントソースをポーリングし、イベントが検出されたら Deployment のレプリカ数を 0 から 1 に変更する
  2. 1→0 スケーリング: イベントが一定期間検出されない場合、レプリカ数を 1 から 0 に変更する(cooldownPeriod に基づく)
  3. HPA の自動管理: ScaledObject が作成されると、対応する HPA を自動的に生成・管理する
  4. ScaledJob の管理: イベントに応じて Kubernetes Job を作成・管理する

Controller Manager は Kubernetes Controller パターンに基づき、以下の CRD をリコンサイルする:

  • ScaledObject
  • ScaledJob
  • TriggerAuthentication
  • ClusterTriggerAuthentication

5.3 keda-operator-metrics-apiserver(Metrics Adapter Server)

Metrics Adapter Server は Kubernetes の External Metrics API (external.metrics.k8s.io) を実装する。これにより、KEDA のスケーラーが収集したメトリクスを HPA が利用できるようになる。

                    HPA
                     │
                     │ External Metrics API
                     │ (GET /apis/external.metrics.k8s.io/v1beta1/...)
                     v
            ┌────────────────────┐
            │ Metrics Adapter    │
            │ Server             │
            │                    │
            │ - APIService 登録  │
            │ - メトリクス提供   │
            │ - 認証/認可        │
            └────────┬───────────┘
                     │
                     │ スケーラーインターフェース
                     v
            ┌────────────────────┐
            │ Scaler Pool        │
            │                    │
            │ - GetMetrics()     │
            │ - IsActive()       │
            │ - GetMetricSpec()  │
            │ - Close()          │
            └────────────────────┘

5.4 Scaler Interface

すべてのスケーラーは以下のインターフェースを実装する(Go 言語):

type Scaler interface {
    // GetMetrics はスケーリング判断に使用するメトリクス値を返す
    GetMetrics(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, error)

    // GetMetricSpecForScaling はこのスケーラーが提供するメトリクスの仕様を返す
    GetMetricSpecForScaling(ctx context.Context) []v2.MetricSpec

    // IsActive はイベントソースにアクティブなイベントがあるかを返す
    // 0→1 スケーリングの判断に使用される
    IsActive(ctx context.Context) (bool, error)

    // Close はスケーラーのリソースをクリーンアップする
    Close(ctx context.Context) error
}

// PushScaler はプッシュベースのスケーラー用インターフェース
type PushScaler interface {
    Scaler
    // Run はプッシュベースのイベント監視を開始する
    Run(ctx context.Context, active chan<- bool)
}

5.5 スケーリングフローの詳細

フェーズ 1: 0→1(Activation)

時系列 ─────────────────────────────────────────────────>

  KEDA Agent          Scaler            Event Source       Deployment
      │                  │                   │                 │
      │  IsActive()      │                   │                 │
      │─────────────────>│                   │                 │
      │                  │  ポーリング        │                 │
      │                  │──────────────────>│                 │
      │                  │  イベントあり      │                 │
      │                  │<──────────────────│                 │
      │  true            │                   │                 │
      │<─────────────────│                   │                 │
      │                                                        │
      │  replicas: 0 → 1                                      │
      │───────────────────────────────────────────────────────>│
      │                                                        │
      │  HPA 作成(minReplicas=1)                             │
      │─────────────> [HPA Created]                            │

フェーズ 2: 1→N(Scale Out)

  HPA              Metrics Adapter     Scaler            Event Source
   │                    │                 │                   │
   │  External Metrics  │                 │                   │
   │───────────────────>│                 │                   │
   │                    │  GetMetrics()   │                   │
   │                    │────────────────>│                   │
   │                    │                 │  メトリクス取得    │
   │                    │                 │──────────────────>│
   │                    │                 │  lag=500          │
   │                    │                 │<──────────────────│
   │                    │  value=500      │                   │
   │                    │<────────────────│                   │
   │  value=500         │                 │                   │
   │<───────────────────│                 │                   │
   │                                                          │
   │  desiredReplicas = ceil(currentReplicas * (500/50))      │
   │  = ceil(1 * 10) = 10                                    │
   │───────────────────────────────────────> [Scale to 10]    │

フェーズ 3: N→1→0(Scale In / Deactivation)

  HPA              KEDA Agent        Scaler             Deployment
   │                    │               │                    │
   │  メトリクス低下     │               │                    │
   │  desiredReplicas=1 │               │                    │
   │──────────────────────────────────────────────────────>  │
   │                    │               │                    │
   │                    │  IsActive()   │                    │
   │                    │──────────────>│                    │
   │                    │  false        │                    │
   │                    │<──────────────│                    │
   │                    │                                    │
   │                    │  cooldownPeriod 待機               │
   │                    │  (デフォルト: 300秒)               │
   │                    │                                    │
   │                    │  replicas: 1 → 0                  │
   │                    │───────────────────────────────────>│
   │                    │                                    │
   │  HPA 削除/無効化   │                                    │
   │<───────────────────│                                    │

5.6 ポーリングモデル

KEDA はイベントソースをポーリング方式で監視する。ポーリング間隔は pollingInterval パラメータで制御される(デフォルト: 30秒)。

spec:
  pollingInterval: 15   # 15秒ごとにイベントソースをチェック
  cooldownPeriod: 300   # 最後のイベントから300秒後にゼロスケール
  minReplicaCount: 0    # 最小レプリカ数(ゼロスケーリング有効)
  maxReplicaCount: 100  # 最大レプリカ数

ポーリングの動作:

  1. pollingInterval ごとに各スケーラーの IsActive()GetMetrics() を呼び出す
  2. IsActive()false → ゼロスケールの候補
  3. IsActive()true → メトリクスを HPA に提供
  4. HPA が標準のアルゴリズムでレプリカ数を決定

注意点:

  • ポーリング間隔を短くするとスケーリングの応答性が向上するが、イベントソースへの負荷が増加する
  • 非常に短い間隔(5秒未満)は推奨されない
  • PushScaler を実装する一部のスケーラーはイベント駆動で通知を受け取る

6. CRD リファレンス

6.1 ScaledObject 完全リファレンス

ScaledObject は Deployment、StatefulSet、またはカスタムリソースのスケーリングを定義する CRD である。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: {scaled-object-name}
  namespace: {namespace}
  labels:
    app: {app-label}                          # 任意のラベル
  annotations:
    scaledobject.keda.sh/transfer-hpa-ownership: "true"  # 既存 HPA の所有権移譲
spec:
  # === スケールターゲット ===
  scaleTargetRef:
    apiVersion: apps/v1                       # デフォルト: apps/v1
    kind: Deployment                          # デフォルト: Deployment
    name: {deployment-name}                   # 必須: ターゲットリソース名
    envSourceContainerName: {container-name}  # 環境変数参照用コンテナ

  # === スケーリングパラメータ ===
  pollingInterval: 30                         # デフォルト: 30(秒)
  cooldownPeriod: 300                         # デフォルト: 300(秒)
  idleReplicaCount: 0                         # オプション: アイドル時のレプリカ数
  minReplicaCount: 0                          # デフォルト: 0
  maxReplicaCount: 100                        # デフォルト: 100
  initialCooldownPeriod: 0                    # デフォルト: 0(秒)起動直後のクールダウン

  # === フォールバック設定 ===
  fallback:
    failureThreshold: 3                       # 失敗回数の閾値
    replicas: 6                               # フォールバック時のレプリカ数

  # === HPA 詳細設定 ===
  advanced:
    restoreToOriginalReplicaCount: false      # ScaledObject 削除時に元のレプリカ数に復元
    horizontalPodAutoscalerConfig:
      name: {custom-hpa-name}                 # カスタム HPA 名
      behavior:                               # HPA v2 の behavior 設定
        scaleUp:
          stabilizationWindowSeconds: 0
          policies:
          - type: Percent
            value: 100
            periodSeconds: 15
          selectPolicy: Max
        scaleDown:
          stabilizationWindowSeconds: 300
          policies:
          - type: Percent
            value: 10
            periodSeconds: 60
          - type: Pods
            value: 5
            periodSeconds: 60
          selectPolicy: Min

  # === トリガー定義 ===
  triggers:
  - type: {scaler-type}                       # 必須: スケーラータイプ
    name: {trigger-name}                      # オプション: トリガー名
    useCachedMetrics: false                   # デフォルト: false
    metadata:
      # スケーラー固有のメタデータ
      key: value
    authenticationRef:                        # オプション: 認証参照
      name: {trigger-auth-name}
      kind: TriggerAuthentication             # または ClusterTriggerAuthentication
    metricType: AverageValue                  # Value, AverageValue, Utilization

6.2 ScaledObject パラメータ詳解

pollingInterval(ポーリング間隔)

イベントソースを確認する間隔(秒)。短い値はスケーリングの応答性を高めるが、イベントソースへの負荷が増える。

用途推奨値
リアルタイム処理5-15秒
一般的なワークロード15-30秒
バッチ処理30-60秒
コスト最適化60-300秒

cooldownPeriod(クールダウン期間)

最後のトリガーがアクティブでなくなってから、レプリカ数をゼロ(または idleReplicaCount)にするまでの待機時間(秒)。

# 短いクールダウン: コスト重視
cooldownPeriod: 60

# 長いクールダウン: 可用性重視(バースト対応)
cooldownPeriod: 600

idleReplicaCount と minReplicaCount

# パターン1: 完全ゼロスケーリング
minReplicaCount: 0
# idleReplicaCount は設定しない(デフォルト: minReplicaCount と同じ)

# パターン2: アイドル時にゼロ、アクティブ時は最低3台
idleReplicaCount: 0    # アイドル時は0
minReplicaCount: 3     # アクティブ時の最小値

# パターン3: 常に最低1台維持(ゼロスケーリング無効)
minReplicaCount: 1

idleReplicaCountminReplicaCount の違い:

  • idleReplicaCount: すべてのトリガーが非アクティブ時のレプリカ数
  • minReplicaCount: HPA の minReplicas に設定される値(アクティブ時の最小値)

initialCooldownPeriod

ScaledObject 作成直後のクールダウン期間。デプロイ直後にスケールダウンされるのを防ぐ。

# デプロイ後120秒間はスケールダウンしない
initialCooldownPeriod: 120

advanced.horizontalPodAutoscalerConfig.behavior

HPA v2 の behavior フィールドをそのまま透過的に設定できる。スケールアップ/ダウンの速度を細かく制御可能。

advanced:
  horizontalPodAutoscalerConfig:
    behavior:
      scaleUp:
        stabilizationWindowSeconds: 0        # スケールアップの安定化ウィンドウ
        policies:
        - type: Percent
          value: 900                          # 現在の900%まで一度にスケールアップ
          periodSeconds: 60
        - type: Pods
          value: 50                           # または50 Pod まで一度にスケールアップ
          periodSeconds: 60
        selectPolicy: Max                     # 最大値ポリシーを選択
      scaleDown:
        stabilizationWindowSeconds: 300       # 300秒の安定化ウィンドウ
        policies:
        - type: Percent
          value: 10                           # 60秒ごとに最大10%スケールダウン
          periodSeconds: 60
        selectPolicy: Min                     # 最小値ポリシーを選択(慎重にスケールダウン)

6.3 ScaledJob 完全リファレンス

ScaledJob はイベントに応じて Kubernetes Job を作成する CRD である。メッセージキューのメッセージごとに独立した Job を起動するようなユースケースに最適。

apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: {scaled-job-name}
  namespace: {namespace}
spec:
  # === Job テンプレート ===
  jobTargetRef:
    parallelism: 1                            # Job の並列度
    completions: 1                            # 完了数
    activeDeadlineSeconds: 600                # Job のタイムアウト
    backoffLimit: 6                           # リトライ回数
    template:
      spec:
        containers:
        - name: worker
          image: my-worker:latest
          command: ["./process-message"]
        restartPolicy: Never

  # === スケーリングパラメータ ===
  pollingInterval: 30                         # デフォルト: 30(秒)
  minReplicaCount: 0                          # デフォルト: 0
  maxReplicaCount: 100                        # デフォルト: 100
  successfulJobsHistoryLimit: 5               # 成功 Job の保持数
  failedJobsHistoryLimit: 5                   # 失敗 Job の保持数

  # === スケーリング戦略 ===
  scalingStrategy:
    strategy: default                         # default, custom, accurate
    # custom 戦略の場合:
    # customScalingQueueLengthDeduction: 1
    # customScalingRunningJobPercentage: "0.5"
    # multi_target 戦略の場合:
    # multipleScalersCalculation: max         # max, min, avg, sum
    # pendingPodConditions:
    # - "Ready"
    # - "PodScheduled"

  # === ロールアウト戦略 ===
  rollout:
    strategy: default                         # default, gradual
    propagationPolicy: Foreground             # Foreground, Background, Orphan

  # === トリガー定義 ===
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: job-processor
      topic: tasks
      lagThreshold: "1"

ScaledJob のスケーリング戦略

戦略説明
default(メトリクス値) / (threshold) で必要な Job 数を計算
custom実行中の Job を考慮した計算
accurate実行中と保留中の Job を厳密に考慮
# accurate 戦略の例
scalingStrategy:
  strategy: accurate
  # 必要 Job 数 = メトリクス値 - 実行中 Job 数 - 保留中 Job 数

6.4 TriggerAuthentication

TriggerAuthentication は名前空間スコープの認証情報を定義する CRD である。

apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: kafka-auth
  namespace: default
spec:
  # === 方式1: Kubernetes Secret 参照 ===
  secretTargetRef:
  - parameter: sasl_username          # トリガーの認証パラメータ名
    name: kafka-credentials           # Secret 名
    key: username                     # Secret 内のキー
  - parameter: sasl_password
    name: kafka-credentials
    key: password

  # === 方式2: 環境変数参照 ===
  env:
  - parameter: connectionString
    name: DB_CONNECTION_STRING        # 環境変数名
    containerName: my-container       # コンテナ名

  # === 方式3: Pod Identity(Azure) ===
  podIdentity:
    provider: azure                   # azure, azure-workload, aws, aws-eks, aws-kiam, gcp
    identityId: {identity-id}         # オプション

  # === 方式4: HashiCorp Vault ===
  hashiCorpVault:
    address: https://vault.example.com
    authentication: token             # token, kubernetes, serviceAccount
    role: my-role                     # kubernetes 認証の場合のロール名
    mount: kubernetes                 # kubernetes 認証のマウントパス
    credential:
      token: vault-token              # token 認証の場合
      serviceAccount: vault-sa        # serviceAccount 認証の場合
    secrets:
    - parameter: password
      key: secret/data/myapp
      path: password
    - parameter: username
      key: secret/data/myapp
      path: username

  # === 方式5: AWS Secret Manager ===
  awsSecretManager:
    credentials:
      accessKey:
        valueFrom:
          secretKeyRef:
            name: aws-credentials
            key: AWS_ACCESS_KEY_ID
      accessSecretKey:
        valueFrom:
          secretKeyRef:
            name: aws-credentials
            key: AWS_SECRET_ACCESS_KEY
    region: ap-northeast-1
    secrets:
    - parameter: connectionString
      name: my-secret
      versionId: latest

6.5 ClusterTriggerAuthentication

ClusterTriggerAuthentication はクラスタスコープの認証情報である。構文は TriggerAuthentication と同一だが、全名前空間から参照可能。

apiVersion: keda.sh/v1alpha1
kind: ClusterTriggerAuthentication
metadata:
  name: global-kafka-auth
  # 名前空間は不要(クラスタスコープ)
spec:
  secretTargetRef:
  - parameter: sasl_username
    name: kafka-credentials
    key: username
  - parameter: sasl_password
    name: kafka-credentials
    key: password

---
# 参照する ScaledObject
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: my-app
  namespace: production
spec:
  scaleTargetRef:
    name: my-app
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: my-group
      topic: events
      lagThreshold: "10"
    authenticationRef:
      name: global-kafka-auth
      kind: ClusterTriggerAuthentication       # ← ClusterTriggerAuthentication を指定

7. スケーラーカタログ

7.1 カテゴリ別一覧

KEDA は 60 以上の組み込みスケーラーを提供する。主要なカテゴリは以下の通り。

メッセージキュー / ストリーミング

スケーラー説明
Apache KafkaConsumer Group のラグに基づくスケーリング
AWS SQSキューの深さに基づくスケーリング
AWS Kinesisシャードあたりのメッセージ数
Azure Service Busメッセージ数/アクティブメッセージ数
Azure Event HubsConsumer Group のラグ
Google Pub/Sub未確認メッセージ数
RabbitMQキューの深さ/メッセージレート
NATS JetStreamストリームの未処理メッセージ
Redis StreamsPending メッセージ数
ActiveMQキューのメッセージ数
IBM MQキューの深さ
Solace PubSub+メッセージ数
Pulsarバックログメッセージ数

データベース

スケーラー説明
PostgreSQLクエリ結果に基づくスケーリング
MySQLクエリ結果に基づくスケーリング
MongoDBクエリ結果に基づくスケーリング
MSSQLクエリ結果に基づくスケーリング
Cassandraクエリ結果に基づくスケーリング
CouchDB保留中の変更数
Elasticsearchクエリ結果に基づくスケーリング
InfluxDBクエリ結果に基づくスケーリング
Etcdキーの値に基づくスケーリング

メトリクス / 監視

スケーラー説明
PrometheusPromQL クエリ結果に基づくスケーリング
Datadogメトリクスクエリに基づくスケーリング
New RelicNRQL クエリに基づくスケーリング
Dynatraceメトリクスに基づくスケーリング
Graphiteクエリに基づくスケーリング
Metrics API任意のメトリクスエンドポイント

クラウドサービス

スケーラー説明
AWS CloudWatchCloudWatch メトリクスに基づくスケーリング
Azure MonitorAzure Monitor メトリクス
Azure Log Analyticsログクエリ結果
GCP StackdriverStackdriver メトリクス
GCP Cloud Tasksタスク数

その他

スケーラー説明
Cron時間ベースのスケーリング
CPU / Memoryリソースベース(HPA 互換)
ExternalgRPC 外部スケーラー
Kubernetes Workload他のワークロードのレプリカ数に基づく
Selenium GridSelenium テストキュー
GitHub Runnerワークフローキュー
LokiLogQL クエリ結果

7.2 Kafka スケーラー詳細設定

Apache Kafka は KEDA で最も一般的に使用されるスケーラーの一つである。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-consumer-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: kafka-consumer
  pollingInterval: 10
  cooldownPeriod: 300
  minReplicaCount: 0
  maxReplicaCount: 50
  triggers:
  - type: kafka
    metadata:
      # === 接続設定 ===
      bootstrapServers: kafka-0.kafka:9092,kafka-1.kafka:9092,kafka-2.kafka:9092
      consumerGroup: order-processor-group
      topic: orders                           # 単一トピック
      # topicPattern: "orders-.*"             # または正規表現パターン

      # === スケーリング設定 ===
      lagThreshold: "50"                      # パーティションあたりのラグ閾値
      activationLagThreshold: "10"            # アクティベーション閾値(0→1用)
      offsetResetPolicy: latest               # latest, earliest

      # === TLS/SASL 設定 ===
      tls: enable                             # enable, disable
      sasl: plaintext                         # plaintext, scram_sha256, scram_sha512, oauthbearer, gssapi

      # === その他 ===
      allowIdleConsumers: "false"             # アイドルコンシューマーを許可
      excludePersistentLag: "false"           # 永続的なラグを除外
      scaleToZeroOnInvalidOffset: "false"     # 無効なオフセット時にゼロスケール
      limitToPartitionsWithLag: "false"       # ラグのあるパーティションのみ考慮
      version: "1.0.0"                        # Kafka プロトコルバージョン

    authenticationRef:
      name: kafka-auth

---
# Kafka 認証設定
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: kafka-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: sasl
    name: kafka-secrets
    key: sasl_mechanism
  - parameter: username
    name: kafka-secrets
    key: sasl_username
  - parameter: password
    name: kafka-secrets
    key: sasl_password
  - parameter: tls
    name: kafka-secrets
    key: tls_enabled
  - parameter: ca
    name: kafka-secrets
    key: ca_cert
  - parameter: cert
    name: kafka-secrets
    key: client_cert
  - parameter: key
    name: kafka-secrets
    key: client_key

---
apiVersion: v1
kind: Secret
metadata:
  name: kafka-secrets
  namespace: production
type: Opaque
data:
  sasl_mechanism: cGxhaW50ZXh0             # plaintext
  sasl_username: a2Fma2EtdXNlcg==          # kafka-user
  sasl_password: c2VjcmV0LXBhc3N3b3Jk      # secret-password
  tls_enabled: ZW5hYmxl                     # enable
  ca_cert: <base64-encoded-ca-cert>
  client_cert: <base64-encoded-client-cert>
  client_key: <base64-encoded-client-key>

Kafka スケーリングの計算式:

desiredReplicas = ceil(totalLag / lagThreshold)

例:
  totalLag = 500(全パーティションの合計ラグ)
  lagThreshold = 50
  desiredReplicas = ceil(500 / 50) = 10

注意点:

  • lagThreshold はパーティションあたりではなく、合計ラグに対する閾値
  • maxReplicaCount はパーティション数以下にすることが推奨される(パーティション数を超えるとアイドルコンシューマーが発生)
  • allowIdleConsumers: "true" を設定するとパーティション数を超えるスケーリングが可能

7.3 Prometheus スケーラー詳細設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: api-server
  pollingInterval: 15
  cooldownPeriod: 120
  minReplicaCount: 2
  maxReplicaCount: 30
  triggers:
  - type: prometheus
    metadata:
      # === 接続設定 ===
      serverAddress: http://prometheus.monitoring.svc.cluster.local:9090
      namespace: production                   # Prometheus ネームスペース(オプション)

      # === クエリ設定 ===
      query: |
        sum(rate(http_requests_total{
          namespace="production",
          service="api-server"
        }[2m]))
      threshold: "100"                        # スケーリング閾値
      activationThreshold: "5"                # アクティベーション閾値

      # === 認証設定 ===
      authModes: "basic"                      # basic, tls, bearer
      unsafeSsl: "false"                      # 自己署名証明書を許可

      # === カスタムヘッダー ===
      customHeaders: "X-Scope-OrgID=my-org"   # マルチテナント Prometheus 用

      # === Cortex/Thanos/Mimir 互換 ===
      cortexOrgID: "my-tenant"                # Cortex/Mimir テナント ID

      # === 欠損値処理 ===
      ignoreNullValues: "true"                # null 結果を無視

    authenticationRef:
      name: prometheus-auth

---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: prometheus-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: username
    name: prometheus-credentials
    key: username
  - parameter: password
    name: prometheus-credentials
    key: password

Prometheus クエリの例:

# リクエストレートに基づくスケーリング
query: sum(rate(http_requests_total{service="my-app"}[2m]))
threshold: "100"

# エラーレートに基づくスケーリング(エラーが多い時にスケールアップ)
query: |
  sum(rate(http_requests_total{service="my-app", status=~"5.."}[5m]))
  / sum(rate(http_requests_total{service="my-app"}[5m])) * 100
threshold: "5"

# キューイング時間に基づくスケーリング
query: histogram_quantile(0.95, rate(request_duration_seconds_bucket{service="my-app"}[5m]))
threshold: "0.5"

# カスタムビジネスメトリクス
query: sum(pending_orders{region="asia"})
threshold: "50"

7.4 PostgreSQL スケーラー詳細設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: postgresql-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: task-processor
  pollingInterval: 30
  cooldownPeriod: 300
  minReplicaCount: 0
  maxReplicaCount: 20
  triggers:
  - type: postgresql
    metadata:
      # === 接続設定 ===
      connectionFromEnv: DATABASE_URL         # 環境変数から接続文字列を取得
      # または
      # host: postgres.default.svc.cluster.local
      # port: "5432"
      # userName: keda_user
      # dbName: mydb
      # sslmode: require

      # === クエリ設定 ===
      query: "SELECT COUNT(*) FROM tasks WHERE status = 'pending'"
      targetQueryValue: "10"                  # 閾値
      activationTargetQueryValue: "1"         # アクティベーション閾値

      # === メトリクスタイプ ===
      metricName: pending-tasks               # カスタムメトリクス名

    authenticationRef:
      name: postgres-auth

---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: postgres-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: connection
    name: postgres-credentials
    key: connection_string

---
apiVersion: v1
kind: Secret
metadata:
  name: postgres-credentials
  namespace: production
type: Opaque
stringData:
  connection_string: "postgresql://keda_user:password@postgres:5432/mydb?sslmode=require"

7.5 Cron スケーラー詳細設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: cron-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: web-server
  minReplicaCount: 1
  maxReplicaCount: 20
  triggers:
  # 営業時間帯にスケールアップ(日本時間)
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: "0 8 * * 1-5"                   # 平日 8:00
      end: "0 20 * * 1-5"                    # 平日 20:00
      desiredReplicas: "10"

  # ランチタイムにさらにスケールアップ
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: "0 11 * * 1-5"                  # 平日 11:00
      end: "0 14 * * 1-5"                    # 平日 14:00
      desiredReplicas: "15"

  # 週末はミニマム
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: "0 0 * * 0,6"                   # 土日
      end: "0 23 * * 0,6"
      desiredReplicas: "2"

7.6 AWS SQS スケーラー詳細設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: sqs-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: message-processor
  pollingInterval: 10
  cooldownPeriod: 120
  minReplicaCount: 0
  maxReplicaCount: 50
  triggers:
  - type: aws-sqs-queue
    metadata:
      # === キュー設定 ===
      queueURL: https://sqs.ap-northeast-1.amazonaws.com/123456789012/my-queue
      # または
      # queueURLFromEnv: SQS_QUEUE_URL
      queueLength: "5"                       # メッセージ数の閾値
      activationQueueLength: "1"             # アクティベーション閾値

      # === AWS 設定 ===
      awsRegion: ap-northeast-1
      # awsEndpoint: ""                      # カスタムエンドポイント(LocalStack等)

      # === スケーリング設定 ===
      scaleOnInFlight: "true"                # InFlight メッセージも考慮
      scaleOnDelayed: "false"                # 遅延メッセージも考慮

    authenticationRef:
      name: aws-auth

---
# AWS 認証(方式1: Secret ベース)
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: aws-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: awsAccessKeyID
    name: aws-credentials
    key: AWS_ACCESS_KEY_ID
  - parameter: awsSecretAccessKey
    name: aws-credentials
    key: AWS_SECRET_ACCESS_KEY
  # - parameter: awsSessionToken       # STS の場合
  #   name: aws-credentials
  #   key: AWS_SESSION_TOKEN

---
# AWS 認証(方式2: IRSA / Pod Identity)
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: aws-irsa-auth
  namespace: production
spec:
  podIdentity:
    provider: aws                            # IRSA を使用
    # identityOwner: operator                # operator が ID を管理
    # roleArn: arn:aws:iam::123456789012:role/my-role  # オプション

7.7 Redis Streams スケーラー詳細設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: redis-streams-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: stream-processor
  pollingInterval: 15
  cooldownPeriod: 180
  minReplicaCount: 0
  maxReplicaCount: 30
  triggers:
  - type: redis-streams
    metadata:
      # === 接続設定 ===
      address: redis-master.redis.svc.cluster.local:6379
      # addressFromEnv: REDIS_URL
      # host: redis-master.redis.svc.cluster.local
      # port: "6379"

      # === ストリーム設定 ===
      stream: mystream                        # ストリーム名
      consumerGroup: my-consumer-group        # コンシューマーグループ名

      # === スケーリング設定 ===
      pendingEntriesCount: "10"               # Pending エントリ数の閾値
      activationLagCount: "3"                 # アクティベーション閾値

      # === TLS/認証 ===
      enableTLS: "true"
      databaseIndex: "0"                      # Redis DB インデックス

    authenticationRef:
      name: redis-auth

---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: redis-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: password
    name: redis-credentials
    key: redis-password

7.8 Metrics API スケーラー詳細設定

任意の HTTP エンドポイントからメトリクスを取得してスケーリングできる汎用スケーラー。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: metrics-api-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: custom-app
  pollingInterval: 15
  cooldownPeriod: 120
  minReplicaCount: 0
  maxReplicaCount: 20
  triggers:
  - type: metrics-api
    metadata:
      # === エンドポイント設定 ===
      url: "https://metrics.example.com/api/v1/pending-jobs"
      # urlFromEnv: METRICS_URL

      # === レスポンス解析 ===
      valueLocation: "data.pendingCount"      # JSONPath 的なドット記法
      targetValue: "10"                       # 閾値
      activationTargetValue: "1"              # アクティベーション閾値

      # === HTTP 設定 ===
      method: "GET"                           # GET, POST
      # body: '{"filter": "active"}'          # POST の場合のボディ

      # === 認証 ===
      authMode: "bearer"                      # bearer, basic, tls, apiKey

    authenticationRef:
      name: metrics-api-auth

---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: metrics-api-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: bearerToken
    name: metrics-api-credentials
    key: token

8. 高度な機能

8.1 複数トリガーと Scaling Modifiers

複数トリガーのデフォルト動作

複数のトリガーを定義した場合、KEDA はデフォルトで各トリガーの中で 最大値 を採用する。

triggers:
- type: kafka
  metadata:
    lagThreshold: "50"    # → desiredReplicas = 5
- type: prometheus
  metadata:
    threshold: "100"      # → desiredReplicas = 8
# 結果: max(5, 8) = 8 レプリカ

Scaling Modifiers(数式ベースのカスタム計算)

Scaling Modifiers を使用すると、複数トリガーのメトリクスを数式で組み合わせて、最終的なスケーリング値を計算できる。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: composite-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: my-app
  minReplicaCount: 1
  maxReplicaCount: 50

  # === Scaling Modifiers ===
  advanced:
    scalingModifiers:
      # 数式定義(トリガー名で参照)
      formula: "(kafka_trigger + prometheus_trigger) / 2"
      target: "10"                            # 数式の結果に対する閾値
      # activationTarget: "1"                 # アクティベーション閾値
      metricType: AverageValue                # Value, AverageValue

  triggers:
  - type: kafka
    name: kafka_trigger                       # ← 数式で参照する名前
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: my-group
      topic: events
      lagThreshold: "1"                       # Modifiers 使用時は "1" にすることが多い
  - type: prometheus
    name: prometheus_trigger                  # ← 数式で参照する名前
    metadata:
      serverAddress: http://prometheus:9090
      query: sum(rate(http_requests_total{app="my-app"}[2m]))
      threshold: "1"                          # Modifiers 使用時は "1" にすることが多い

Scaling Modifiers の数式例:

# 加重平均
formula: "(kafka_trigger * 0.7 + prometheus_trigger * 0.3)"

# 条件付き(三項演算子的)
formula: "kafka_trigger > 100 ? kafka_trigger : prometheus_trigger"

# 合計
formula: "kafka_trigger + cron_trigger + prometheus_trigger"

# 最小値
formula: "min(kafka_trigger, prometheus_trigger)"

# 最大値
formula: "max(kafka_trigger, prometheus_trigger)"

# 複合計算
formula: "ceil((kafka_trigger * 0.5 + prometheus_trigger) / 2)"

8.2 Pause(一時停止)と Resume(再開)

ScaledObject のアノテーションを使用して、スケーリングを一時停止・再開できる。

# スケーリングを一時停止
kubectl annotate scaledobject my-scaler \
  autoscaling.keda.sh/paused-replicas="5"

# 一時停止解除
kubectl annotate scaledobject my-scaler \
  autoscaling.keda.sh/paused-replicas-

# レプリカ数を0に固定(メンテナンス時)
kubectl annotate scaledobject my-scaler \
  autoscaling.keda.sh/paused-replicas="0"

paused-replicas アノテーションを設定すると:

  1. KEDA はスケーリングを停止する
  2. レプリカ数が指定値に固定される
  3. HPA は無効化される
  4. アノテーションを削除すると通常のスケーリングが再開される

ユースケース:

  • デプロイ中のスケーリング停止
  • トラブルシューティング中の状態固定
  • メンテナンスウィンドウでの制御

8.3 Fallback(フォールバック)

スケーラーがイベントソースに接続できない場合のフォールバック動作を定義できる。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: fallback-example
spec:
  scaleTargetRef:
    name: my-app
  fallback:
    failureThreshold: 3                       # 連続失敗回数の閾値
    replicas: 6                               # フォールバック時のレプリカ数
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: my-group
      topic: orders
      lagThreshold: "50"

フォールバックの動作:

正常動作        Scaler エラー       3回連続失敗        復旧
    │               │                   │              │
    v               v                   v              v
 [動的スケール] → [リトライ] → [フォールバック] → [動的スケール]
                                  replicas=6

注意点:

  • フォールバックは minReplicaCountmaxReplicaCount の範囲内で適用される
  • failureThreshold に達するまでは最後に成功したメトリクス値が使用される
  • スケーラーが復旧すると自動的に通常動作に戻る

8.4 External Scaler(外部スケーラー)

組み込みスケーラーでカバーされないユースケースに対応するため、gRPC ベースの External Scaler を実装できる。

gRPC プロトコル定義

syntax = "proto3";

package externalscaler;

service ExternalScaler {
    // IsActive は 0→1 スケーリングの判断に使用される
    rpc IsActive(ScaledObjectRef) returns (IsActiveResponse) {}

    // StreamIsActive はプッシュベースの IsActive
    rpc StreamIsActive(ScaledObjectRef) returns (stream IsActiveResponse) {}

    // GetMetricSpec はメトリクスの仕様を返す
    rpc GetMetricSpec(ScaledObjectRef) returns (GetMetricSpecResponse) {}

    // GetMetrics はメトリクス値を返す
    rpc GetMetrics(GetMetricsRequest) returns (GetMetricsResponse) {}
}

message ScaledObjectRef {
    string name = 1;
    string namespace = 2;
    map<string, string> scalerMetadata = 3;
}

message IsActiveResponse {
    bool result = 1;
}

message GetMetricSpecResponse {
    repeated MetricSpec metricSpecs = 1;
}

message MetricSpec {
    string metricName = 1;
    int64 targetSize = 2;
}

message GetMetricsRequest {
    ScaledObjectRef scaledObjectRef = 1;
    string metricName = 2;
}

message GetMetricsResponse {
    repeated MetricValue metricValues = 1;
}

message MetricValue {
    string metricName = 1;
    int64 metricValue = 2;
}

Python 実装例

import grpc
from concurrent import futures
import time
import logging
import requests

# 生成された protobuf モジュール
import externalscaler_pb2
import externalscaler_pb2_grpc

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class ExternalScalerServicer(externalscaler_pb2_grpc.ExternalScalerServicer):
    """カスタムビジネスロジックに基づく External Scaler の実装例"""

    def IsActive(self, request, context):
        """イベントソースがアクティブかどうかを判定"""
        metadata = request.scalerMetadata
        api_url = metadata.get("apiUrl", "http://localhost:8080/metrics")
        threshold = int(metadata.get("activationThreshold", "1"))

        try:
            response = requests.get(api_url, timeout=5)
            data = response.json()
            pending_count = data.get("pendingItems", 0)

            is_active = pending_count >= threshold
            logger.info(
                f"IsActive check: pending={pending_count}, "
                f"threshold={threshold}, active={is_active}"
            )
            return externalscaler_pb2.IsActiveResponse(result=is_active)

        except Exception as e:
            logger.error(f"Error checking IsActive: {e}")
            # エラー時はアクティブとみなす(安全側に倒す)
            return externalscaler_pb2.IsActiveResponse(result=True)

    def StreamIsActive(self, request, context):
        """プッシュベースの IsActive ストリーム"""
        while context.is_active():
            response = self.IsActive(request, context)
            yield response
            time.sleep(10)  # 10秒ごとにチェック

    def GetMetricSpec(self, request, context):
        """メトリクス仕様を返す"""
        metadata = request.scalerMetadata
        metric_name = metadata.get("metricName", "custom_metric")
        target_value = int(metadata.get("targetValue", "10"))

        spec = externalscaler_pb2.MetricSpec(
            metricName=metric_name,
            targetSize=target_value
        )
        return externalscaler_pb2.GetMetricSpecResponse(metricSpecs=[spec])

    def GetMetrics(self, request, context):
        """現在のメトリクス値を返す"""
        metadata = request.scaledObjectRef.scalerMetadata
        api_url = metadata.get("apiUrl", "http://localhost:8080/metrics")
        metric_name = request.metricName

        try:
            response = requests.get(api_url, timeout=5)
            data = response.json()
            value = data.get("pendingItems", 0)

            logger.info(f"GetMetrics: {metric_name}={value}")
            metric_value = externalscaler_pb2.MetricValue(
                metricName=metric_name,
                metricValue=value
            )
            return externalscaler_pb2.GetMetricsResponse(
                metricValues=[metric_value]
            )

        except Exception as e:
            logger.error(f"Error getting metrics: {e}")
            context.set_code(grpc.StatusCode.INTERNAL)
            context.set_details(str(e))
            return externalscaler_pb2.GetMetricsResponse()


def serve():
    server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=10),
        options=[
            ('grpc.max_send_message_length', 50 * 1024 * 1024),
            ('grpc.max_receive_message_length', 50 * 1024 * 1024),
        ]
    )
    externalscaler_pb2_grpc.add_ExternalScalerServicer_to_server(
        ExternalScalerServicer(), server
    )
    server.add_insecure_port('[::]:50051')
    logger.info("External Scaler server starting on port 50051")
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    serve()

External Scaler の ScaledObject 設定

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: external-scaler-example
  namespace: production
spec:
  scaleTargetRef:
    name: my-app
  pollingInterval: 10
  cooldownPeriod: 60
  minReplicaCount: 0
  maxReplicaCount: 50
  triggers:
  - type: external
    metadata:
      scalerAddress: external-scaler.keda.svc.cluster.local:50051
      # スケーラーに渡すメタデータ
      apiUrl: "http://business-api:8080/metrics"
      metricName: "pending_items"
      targetValue: "10"
      activationThreshold: "1"

---
# External Scaler の Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-scaler
  namespace: keda
spec:
  replicas: 2
  selector:
    matchLabels:
      app: external-scaler
  template:
    metadata:
      labels:
        app: external-scaler
    spec:
      containers:
      - name: scaler
        image: my-registry/external-scaler:v1.0
        ports:
        - containerPort: 50051
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi

---
apiVersion: v1
kind: Service
metadata:
  name: external-scaler
  namespace: keda
spec:
  selector:
    app: external-scaler
  ports:
  - port: 50051
    targetPort: 50051

8.5 HTTP Add-on

KEDA HTTP Add-on は HTTP トラフィックに基づくゼロスケーリングを実現するオプションコンポーネントである。

                    ┌──────────────────┐
                    │  Ingress /       │
                    │  Service         │
                    └────────┬─────────┘
                             │
                             v
                    ┌──────────────────┐
                    │  KEDA HTTP       │
                    │  Interceptor     │
                    │  Proxy           │
                    │                  │
                    │  - リクエスト     │
                    │    カウント       │
                    │  - キューイング   │
                    │  - フォワード     │
                    └────────┬─────────┘
                             │
                    ┌────────┴─────────┐
                    │                  │
                    v                  v
            ┌──────────────┐  ┌──────────────┐
            │  App Pod 1   │  │  App Pod 2   │
            │              │  │              │
            └──────────────┘  └──────────────┘
# HTTP Add-on のインストール
# helm repo add kedacore https://kedacore.github.io/charts
# helm install http-add-on kedacore/keda-add-ons-http --namespace keda

---
apiVersion: http.keda.sh/v1alpha1
kind: HTTPScaledObject
metadata:
  name: my-http-app
  namespace: production
spec:
  hosts:
  - "api.example.com"
  pathPrefixes:
  - "/api/v1"
  scaleTargetRef:
    name: my-http-app
    kind: Deployment
    apiVersion: apps/v1
    service: my-http-app-svc
    port: 8080
  replicas:
    min: 0
    max: 30
  scalingMetric:
    requestRate:
      targetValue: 100                        # 1 Pod あたり 100 req/s
      granularity: 1s
      window: 1m
    concurrency:
      targetValue: 50                         # 1 Pod あたり同時接続 50
  scaledownPeriod: 300

9. インストールと構成

9.1 Helm によるインストール(推奨)

# Helm リポジトリの追加
helm repo add kedacore https://kedacore.github.io/charts
helm repo update

# 名前空間の作成
kubectl create namespace keda

# KEDA のインストール(プロダクション設定)
helm install keda kedacore/keda \
  --namespace keda \
  --version 2.14.0 \
  --values keda-values.yaml

プロダクション用 Helm Values

# keda-values.yaml - プロダクション環境向け設定
image:
  keda:
    tag: "2.14.0"
  metricsApiServer:
    tag: "2.14.0"

# Operator の設定
operator:
  name: keda-operator
  replicaCount: 2                             # 高可用性のため2レプリカ

  # リソース設定
  resources:
    requests:
      cpu: 100m
      memory: 256Mi
    limits:
      cpu: 1000m
      memory: 1Gi

  # Pod Disruption Budget
  podDisruptionBudget:
    minAvailable: 1

  # アフィニティ設定(異なるノードに分散)
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: keda-operator
          topologyKey: kubernetes.io/hostname

  # Tolerations(専用ノードプール用)
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "keda"
    effect: "NoSchedule"

  # Node Selector
  nodeSelector:
    node-role: infra

# Metrics Server の設定
metricsServer:
  replicaCount: 2                             # 高可用性
  resources:
    requests:
      cpu: 100m
      memory: 256Mi
    limits:
      cpu: 1000m
      memory: 512Mi

  # Pod Disruption Budget
  podDisruptionBudget:
    minAvailable: 1

  # アフィニティ
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: keda-operator-metrics-apiserver
          topologyKey: kubernetes.io/hostname

# Webhook の設定
webhooks:
  enabled: true
  port: 9443

# Prometheus メトリクス
prometheus:
  metricServer:
    enabled: true
    port: 8080
    portName: metrics
    path: /metrics
    serviceMonitor:
      enabled: true                           # ServiceMonitor を自動作成
      namespace: monitoring
      additionalLabels:
        release: prometheus
    podMonitor:
      enabled: false
  operator:
    enabled: true
    port: 8080
    serviceMonitor:
      enabled: true
      namespace: monitoring
      additionalLabels:
        release: prometheus

# RBAC 設定
rbac:
  create: true

# Service Account
serviceAccount:
  create: true
  name: keda-operator
  annotations: {}
    # AWS IRSA の場合:
    # eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/keda-role

# Pod Security
podSecurityContext:
  operator:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
  metricsServer:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000

# 証明書管理
certificates:
  autoGenerated: true
  # cert-manager を使用する場合:
  # certManager:
  #   enabled: true
  #   generateCA: false

# ログ設定
logging:
  operator:
    level: info                               # debug, info, error
    format: json                              # console, json
    timeEncoding: iso8601                     # iso8601, epoch
  metricsServer:
    level: "0"                                # 0 = info
  webhooks:
    level: info

# グローバル設定
extraArgs:
  keda:
    # カスタム CRD 管理
    enable-cert-rotation: true
    cert-dir: /certs
    # メトリクスサーバー接続
    metrics-server-dns-policy: ClusterFirst

# ウォッチ対象の名前空間制限(オプション)
watchNamespace: ""                            # 空 = 全名前空間

9.2 YAML マニフェストによるインストール

# 特定バージョンのマニフェストを適用
kubectl apply --server-side \
  -f https://github.com/kedacore/keda/releases/download/v2.14.0/keda-2.14.0.yaml

# CRD のみインストール
kubectl apply --server-side \
  -f https://github.com/kedacore/keda/releases/download/v2.14.0/keda-2.14.0-crds.yaml

9.3 インストールの検証

# KEDA コンポーネントの確認
kubectl get pods -n keda
# 期待される出力:
# NAME                                               READY   STATUS    RESTARTS   AGE
# keda-operator-xxxxxxxxx-xxxxx                      1/1     Running   0          1m
# keda-operator-xxxxxxxxx-xxxxx                      1/1     Running   0          1m
# keda-operator-metrics-apiserver-xxxxxxxxx-xxxxx    1/1     Running   0          1m
# keda-operator-metrics-apiserver-xxxxxxxxx-xxxxx    1/1     Running   0          1m

# CRD の確認
kubectl get crd | grep keda
# 期待される出力:
# clustertriggerauthentications.keda.sh   2024-xx-xx
# scaledjobs.keda.sh                      2024-xx-xx
# scaledobjects.keda.sh                   2024-xx-xx
# triggerauthentications.keda.sh          2024-xx-xx

# API Service の確認
kubectl get apiservice v1beta1.external.metrics.k8s.io
# 期待される出力:
# NAME                                SERVICE                              AVAILABLE
# v1beta1.external.metrics.k8s.io   keda/keda-operator-metrics-apiserver   True

# Webhook の確認
kubectl get validatingwebhookconfigurations | grep keda

# テスト用 ScaledObject のデプロイ
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: keda-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keda-test
  template:
    metadata:
      labels:
        app: keda-test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: keda-test
spec:
  scaleTargetRef:
    name: keda-test
  minReplicaCount: 0
  maxReplicaCount: 5
  triggers:
  - type: cron
    metadata:
      timezone: UTC
      start: "0 0 * * *"
      end: "59 23 * * *"
      desiredReplicas: "1"
EOF

# ScaledObject のステータス確認
kubectl get scaledobject keda-test
kubectl describe scaledobject keda-test

# クリーンアップ
kubectl delete scaledobject keda-test
kubectl delete deployment keda-test

10. モニタリングとオブザーバビリティ

10.1 KEDA の Prometheus メトリクス

KEDA は以下の Prometheus メトリクスを公開する:

Operator メトリクス

メトリクスタイプ説明
keda_scaledobject_readyGaugeScaledObject の準備状態
keda_scaledobject_pausedGaugeScaledObject の一時停止状態
keda_scaled_object_errorsCounterScaledObject のエラー数
keda_scaledjob_readyGaugeScaledJob の準備状態
keda_trigger_totalsGauge登録されたトリガーの総数
keda_internal_scale_loop_latencyHistogramスケーリングループの遅延
keda_resource_totalsGaugeKEDA リソースの総数
keda_build_infoGaugeビルド情報

Metrics Server メトリクス

メトリクスタイプ説明
keda_scaler_activeGaugeスケーラーのアクティブ状態
keda_scaler_metrics_valueGaugeスケーラーの現在のメトリクス値
keda_scaler_metrics_latencyHistogramメトリクス取得の遅延
keda_scaler_errorsCounterスケーラーのエラー数
keda_scaler_errors_totalCounterスケーラーのエラー総数

10.2 Grafana ダッシュボード用 PromQL クエリ

KEDA 全体の健全性

# アクティブな ScaledObject 数
count(keda_scaledobject_ready{ready="true"})

# エラー状態の ScaledObject
count(keda_scaledobject_ready{ready="false"})

# 一時停止中の ScaledObject
count(keda_scaledobject_paused{paused="true"})

# KEDA Operator のエラーレート
rate(keda_scaled_object_errors[5m])

# スケーリングループの P95 遅延
histogram_quantile(0.95, rate(keda_internal_scale_loop_latency_bucket[5m]))

スケーラーのパフォーマンス

# 各スケーラーの現在のメトリクス値
keda_scaler_metrics_value{
  namespace="production",
  scaledObject="my-scaler"
}

# スケーラーのアクティブ状態
keda_scaler_active{
  namespace="production",
  scaledObject="my-scaler"
}

# メトリクス取得の遅延(P99)
histogram_quantile(0.99,
  rate(keda_scaler_metrics_latency_bucket[5m])
)

# スケーラーのエラーレート
rate(keda_scaler_errors_total[5m])

# 特定スケーラーのエラー詳細
rate(keda_scaler_errors_total{
  scaler="kafka",
  namespace="production"
}[5m])

スケーリング動作の監視

# Deployment のレプリカ数推移
kube_deployment_spec_replicas{
  namespace="production",
  deployment="my-app"
}

# HPA の desired replicas
kube_horizontalpodautoscaler_spec_target_metric{
  namespace="production",
  horizontalpodautoscaler=~"keda-hpa-.*"
}

# HPA の現在のレプリカ数
kube_horizontalpodautoscaler_status_current_replicas{
  namespace="production",
  horizontalpodautoscaler=~"keda-hpa-.*"
}

10.3 アラートルール

# PrometheusRule for KEDA
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: keda-alerts
  namespace: monitoring
  labels:
    release: prometheus
spec:
  groups:
  - name: keda.rules
    rules:
    # ScaledObject がエラー状態
    - alert: KEDAScaledObjectError
      expr: keda_scaledobject_ready{ready="false"} == 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "ScaledObject {{ $labels.scaledObject }} in {{ $labels.namespace }} is not ready"
        description: "ScaledObject has been in error state for more than 5 minutes."

    # スケーラーのエラーレートが高い
    - alert: KEDAScalerHighErrorRate
      expr: rate(keda_scaler_errors_total[5m]) > 0.5
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "High scaler error rate for {{ $labels.scaler }} in {{ $labels.namespace }}"
        description: "Scaler error rate is {{ $value }} errors/sec."

    # メトリクス取得の遅延が高い
    - alert: KEDAMetricsLatencyHigh
      expr: histogram_quantile(0.99, rate(keda_scaler_metrics_latency_bucket[5m])) > 5
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "High metrics latency for scaler {{ $labels.scaler }}"
        description: "P99 latency is {{ $value }} seconds."

    # KEDA Operator が停止
    - alert: KEDAOperatorDown
      expr: absent(up{job="keda-operator"} == 1)
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "KEDA Operator is down"
        description: "KEDA Operator has been down for more than 5 minutes."

    # KEDA Metrics Server が停止
    - alert: KEDAMetricsServerDown
      expr: absent(up{job="keda-operator-metrics-apiserver"} == 1)
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "KEDA Metrics Server is down"
        description: "Metrics Adapter Server has been down for more than 5 minutes."

    # スケーリングループの遅延が高い
    - alert: KEDAScalingLoopLatencyHigh
      expr: histogram_quantile(0.95, rate(keda_internal_scale_loop_latency_bucket[5m])) > 10
      for: 15m
      labels:
        severity: warning
      annotations:
        summary: "KEDA scaling loop latency is high"
        description: "P95 scaling loop latency is {{ $value }} seconds."

11. トラブルシューティング

11.1 一般的な問題と対処法

問題1: ScaledObject が Ready にならない

# ステータスの確認
kubectl get scaledobject my-scaler -o yaml
kubectl describe scaledobject my-scaler

# Operator ログの確認
kubectl logs -n keda -l app=keda-operator --tail=100 -f

# イベントの確認
kubectl get events --field-selector involvedObject.name=my-scaler

一般的な原因:

  • トリガーの設定パラメータが不正
  • イベントソースへの接続失敗
  • 認証情報の誤り
  • ターゲット Deployment が存在しない

問題2: スケーリングが動作しない

# HPA の確認
kubectl get hpa -l scaledobject.keda.sh/name=my-scaler
kubectl describe hpa keda-hpa-my-scaler

# External Metrics の確認
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/s0-kafka-my-topic"

# Metrics Server ログの確認
kubectl logs -n keda -l app=keda-operator-metrics-apiserver --tail=100

一般的な原因:

  • Metrics Server が External Metrics を提供できていない
  • HPA が作成されていない
  • maxReplicaCount に達している
  • cooldownPeriod 中

問題3: ゼロスケーリングが動作しない

# ScaledObject の設定確認
kubectl get scaledobject my-scaler -o jsonpath='{.spec.minReplicaCount}'
kubectl get scaledobject my-scaler -o jsonpath='{.spec.cooldownPeriod}'

# スケーラーのアクティブ状態確認
kubectl get scaledobject my-scaler -o jsonpath='{.status.conditions}'

一般的な原因:

  • minReplicaCount が 0 でない
  • cooldownPeriod がまだ経過していない
  • スケーラーが常に active を返している
  • idleReplicaCount が設定されていない

問題4: Metrics Server の APIService が Available でない

# APIService の確認
kubectl get apiservice v1beta1.external.metrics.k8s.io -o yaml

# Metrics Server Pod の確認
kubectl get pods -n keda -l app=keda-operator-metrics-apiserver
kubectl logs -n keda -l app=keda-operator-metrics-apiserver

# Service の確認
kubectl get svc -n keda keda-operator-metrics-apiserver

一般的な原因:

  • Metrics Server Pod が起動していない
  • 証明書の問題
  • ネットワークポリシーによるブロック
  • Service のエンドポイントが正しくない

11.2 デバッグ用コマンド集

# === KEDA リソースの全体確認 ===
kubectl get scaledobjects -A
kubectl get scaledjobs -A
kubectl get triggerauthentications -A
kubectl get clustertriggerauthentications

# === 特定の ScaledObject の詳細 ===
kubectl describe scaledobject <name> -n <namespace>

# === KEDA が作成した HPA の確認 ===
kubectl get hpa -A -l scaledobject.keda.sh/name

# === External Metrics API の直接呼び出し ===
# すべての外部メトリクス一覧
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .

# 特定のメトリクス値
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/<ns>/s0-<scaler>-<name>" | jq .

# === ログの確認 ===
# Operator ログ(詳細)
kubectl logs -n keda deployment/keda-operator -c keda-operator --tail=200

# Metrics Server ログ
kubectl logs -n keda deployment/keda-operator-metrics-apiserver --tail=200

# === イベント ===
kubectl get events -n <namespace> --sort-by='.lastTimestamp' | grep -i keda

# === KEDA のバージョン確認 ===
kubectl get deployment -n keda keda-operator -o jsonpath='{.spec.template.spec.containers[0].image}'

11.3 よくあるエラーメッセージと対処

エラーメッセージ原因対処法
no scaler found for typeサポートされていないスケーラータイプスケーラータイプ名のスペルを確認
error getting scaler metricsイベントソースへの接続失敗接続設定と認証を確認
failed to get external metricMetrics API のエラーMetrics Server のログを確認
target not foundターゲットリソースが存在しないDeployment/StatefulSet の名前を確認
permission deniedRBAC 権限不足ServiceAccount と Role を確認
certificate signed by unknown authorityTLS 証明書の問題CA 証明書の設定を確認

12. 実践的ユースケース

12.1 マイクロサービスのイベント駆動パイプライン

                    ┌─────────────┐
                    │  API Gateway │
                    └──────┬──────┘
                           │ HTTP
                           v
┌──────────────────────────────────────────────────────┐
│                    Kafka Cluster                      │
│  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │
│  │ orders   │  │ payments │  │ notifications     │  │
│  │ topic    │  │ topic    │  │ topic             │  │
│  └──────────┘  └──────────┘  └───────────────────┘  │
└──────────┬──────────┬──────────────────┬─────────────┘
           │          │                  │
           v          v                  v
    ┌────────────┐ ┌────────────┐ ┌────────────────┐
    │ Order      │ │ Payment    │ │ Notification   │
    │ Processor  │ │ Processor  │ │ Service        │
    │ (0-20)     │ │ (0-10)     │ │ (0-15)         │
    │ KEDA       │ │ KEDA       │ │ KEDA           │
    └────────────┘ └────────────┘ └────────────────┘
# Order Processor の ScaledObject
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: order-processor
  namespace: production
spec:
  scaleTargetRef:
    name: order-processor
  pollingInterval: 10
  cooldownPeriod: 120
  minReplicaCount: 0
  maxReplicaCount: 20
  advanced:
    horizontalPodAutoscalerConfig:
      behavior:
        scaleUp:
          stabilizationWindowSeconds: 0
          policies:
          - type: Percent
            value: 200
            periodSeconds: 30
        scaleDown:
          stabilizationWindowSeconds: 120
          policies:
          - type: Percent
            value: 25
            periodSeconds: 60
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka.kafka.svc:9092
      consumerGroup: order-processor
      topic: orders
      lagThreshold: "20"
      activationLagThreshold: "5"
    authenticationRef:
      name: kafka-auth

---
# Payment Processor の ScaledObject
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: payment-processor
  namespace: production
spec:
  scaleTargetRef:
    name: payment-processor
  pollingInterval: 10
  cooldownPeriod: 60
  minReplicaCount: 1                          # 決済は常に1台は維持
  maxReplicaCount: 10
  fallback:
    failureThreshold: 3
    replicas: 3                               # Kafka 接続エラー時は3台で運用
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka.kafka.svc:9092
      consumerGroup: payment-processor
      topic: payments
      lagThreshold: "10"
    authenticationRef:
      name: kafka-auth

12.2 夜間ゼロスケーリングによるコスト最適化

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: cost-optimized-app
  namespace: staging
spec:
  scaleTargetRef:
    name: staging-app
  pollingInterval: 30
  cooldownPeriod: 300
  minReplicaCount: 0
  maxReplicaCount: 10
  triggers:
  # 営業時間帯は最低3台
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: "0 8 * * 1-5"
      end: "0 22 * * 1-5"
      desiredReplicas: "3"

  # 実際の負荷に応じてスケール
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      query: |
        sum(rate(http_requests_total{
          namespace="staging",
          service="staging-app"
        }[5m]))
      threshold: "50"
      activationThreshold: "1"

  # 週末は完全ゼロスケール(Cron トリガーなし)
  # → Prometheus トリガーの activationThreshold で制御

コスト削減の試算例:

前提条件:
  - Pod 1台のコスト: $0.05/時間
  - 営業時間帯: 8:00-22:00(14時間/日 × 5日)
  - 平均 Pod 数: 5台

従来(HPA minReplicas=1):
  - 24時間 × 7日 × 1台 × $0.05 = $8.40/週(最低コスト)
  - 営業時間帯: 70時間 × 5台 × $0.05 = $17.50/週
  - 合計: 約 $25.90/週

KEDA(ゼロスケーリング):
  - 営業時間帯: 70時間 × 5台 × $0.05 = $17.50/週
  - 営業外: $0(ゼロスケール)
  - 合計: 約 $17.50/週

削減率: 約 32% のコスト削減

12.3 CI/CD ランナーのスケーリング

# GitHub Actions Self-hosted Runner の KEDA スケーリング
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: github-runner
  namespace: ci
spec:
  jobTargetRef:
    parallelism: 1
    completions: 1
    activeDeadlineSeconds: 3600
    backoffLimit: 0
    template:
      spec:
        serviceAccountName: github-runner
        containers:
        - name: runner
          image: myregistry/github-runner:latest
          env:
          - name: GITHUB_TOKEN
            valueFrom:
              secretKeyRef:
                name: github-runner-secrets
                key: token
          - name: RUNNER_REPOSITORY_URL
            value: "https://github.com/my-org/my-repo"
          resources:
            requests:
              cpu: "2"
              memory: 4Gi
            limits:
              cpu: "4"
              memory: 8Gi
        restartPolicy: Never
  pollingInterval: 15
  minReplicaCount: 0
  maxReplicaCount: 20
  successfulJobsHistoryLimit: 5
  failedJobsHistoryLimit: 5
  scalingStrategy:
    strategy: accurate
  triggers:
  - type: github-runner
    metadata:
      owner: "my-org"
      repos: "my-repo"
      targetWorkflowQueueLength: "1"
    authenticationRef:
      name: github-auth

---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: github-auth
  namespace: ci
spec:
  secretTargetRef:
  - parameter: personalAccessToken
    name: github-runner-secrets
    key: token

12.4 マルチクラスタ構成での考慮事項

                    ┌────────────────────┐
                    │   Global Load      │
                    │   Balancer         │
                    └─────────┬──────────┘
                              │
                    ┌─────────┴──────────┐
                    │                    │
           ┌────────┴────────┐  ┌───────┴─────────┐
           │  Cluster A      │  │  Cluster B       │
           │  (Primary)      │  │  (DR)            │
           │                 │  │                  │
           │  ┌───────────┐  │  │  ┌───────────┐  │
           │  │ KEDA      │  │  │  │ KEDA      │  │
           │  │ Operator  │  │  │  │ Operator  │  │
           │  └─────┬─────┘  │  │  └─────┬─────┘  │
           │        │        │  │        │        │
           │  ┌─────┴─────┐  │  │  ┌─────┴─────┐  │
           │  │ ScaledObj │  │  │  │ ScaledObj │  │
           │  │ min=2     │  │  │  │ min=0     │  │
           │  │ max=50    │  │  │  │ max=50    │  │
           │  └───────────┘  │  │  └───────────┘  │
           └─────────────────┘  └─────────────────┘

マルチクラスタでの注意点:

  1. イベントソースの共有: 複数クラスタが同じ Kafka/SQS を参照する場合、Consumer Group の設計が重要
  2. スケーリングの競合: 各クラスタが独立にスケーリングするため、全体のキャパシティ管理が必要
  3. フェイルオーバー: プライマリクラスタ障害時に DR クラスタが自動的にスケールアップ
  4. メトリクスの集約: Thanos や Cortex で複数クラスタのメトリクスを統合

13. セキュリティとベストプラクティス

13.1 RBAC の最小権限原則

# KEDA 用の制限付き ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: keda-limited
  namespace: keda

---
# 名前空間スコープの Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: keda-limited-role
  namespace: production
rules:
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "patch"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling"]
  resources: ["horizontalpodautoscalers"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

13.2 Secret 管理のベストプラクティス

# 推奨: External Secrets Operator との連携
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: kafka-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: kafka-credentials
  data:
  - secretKey: sasl_username
    remoteRef:
      key: /production/kafka/credentials
      property: username
  - secretKey: sasl_password
    remoteRef:
      key: /production/kafka/credentials
      property: password

---
# TriggerAuthentication で参照
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: kafka-auth
  namespace: production
spec:
  secretTargetRef:
  - parameter: username
    name: kafka-credentials
    key: sasl_username
  - parameter: password
    name: kafka-credentials
    key: sasl_password

13.3 ネットワークポリシー

# KEDA Operator のネットワークポリシー
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: keda-operator-policy
  namespace: keda
spec:
  podSelector:
    matchLabels:
      app: keda-operator
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - port: 9443
      protocol: TCP
  egress:
  # Kubernetes API Server
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - port: 443
      protocol: TCP
    - port: 6443
      protocol: TCP
  # イベントソースへのアクセス
  - to:
    - namespaceSelector: {}
    ports:
    - port: 9092    # Kafka
    - port: 5432    # PostgreSQL
    - port: 6379    # Redis
    - port: 9090    # Prometheus
  # DNS
  - to:
    - namespaceSelector: {}
    ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

13.4 一般的なベストプラクティス

  1. 名前空間分離: KEDA コンポーネントは専用の名前空間(keda)にデプロイする
  2. リソース制限: Operator と Metrics Server にリソースリクエスト/リミットを設定する
  3. 高可用性: プロダクションでは Operator と Metrics Server を各2レプリカ以上にする
  4. 監視: Prometheus メトリクスとアラートを設定する
  5. バージョン管理: KEDA のバージョンを固定し、計画的にアップグレードする
  6. テスト: ステージング環境でスケーリング動作をテストしてからプロダクションに適用する
  7. Fallback 設定: 重要なワークロードには必ず Fallback を設定する
  8. cooldownPeriod: ワークロード特性に応じて適切な値を設定する(頻繁なスケーリングの回避)
  9. maxReplicaCount: 必ず上限を設定し、暴走を防止する
  10. ログレベル: 通常は info にし、デバッグ時のみ debug にする

14. パフォーマンスチューニング

14.1 ポーリング間隔の最適化

# 高レスポンス要求(リアルタイムメッセージ処理)
pollingInterval: 5
cooldownPeriod: 30

# 標準的なウェブアプリケーション
pollingInterval: 15
cooldownPeriod: 120

# バッチ処理(コスト重視)
pollingInterval: 60
cooldownPeriod: 600

14.2 HPA Behavior のチューニング

advanced:
  horizontalPodAutoscalerConfig:
    behavior:
      # === 急速スケールアップ(バースト対応) ===
      scaleUp:
        stabilizationWindowSeconds: 0         # 即座にスケールアップ
        policies:
        - type: Pods
          value: 50                           # 一度に最大50 Pod
          periodSeconds: 30
        - type: Percent
          value: 500                          # 現在の500%まで
          periodSeconds: 30
        selectPolicy: Max

      # === 慎重なスケールダウン(安定性重視) ===
      scaleDown:
        stabilizationWindowSeconds: 300       # 5分間の安定化ウィンドウ
        policies:
        - type: Percent
          value: 10                           # 60秒ごとに最大10%
          periodSeconds: 60
        selectPolicy: Min

14.3 大規模環境でのチューニング

# Operator のリソースを増加
operator:
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi

# Metrics Server のリソースを増加
metricsServer:
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 1Gi

14.4 キャッシュメトリクスの活用

頻繁にメトリクスを取得する必要がない場合、キャッシュを有効にすることでイベントソースへの負荷を軽減できる。

triggers:
- type: prometheus
  useCachedMetrics: true                      # メトリクスキャッシュを有効化
  metadata:
    serverAddress: http://prometheus:9090
    query: sum(rate(http_requests_total[5m]))
    threshold: "100"

useCachedMetrics: true の場合、ポーリング間隔で取得したメトリクスをキャッシュし、HPA からのメトリクスリクエストにはキャッシュ値を返す。


15. エコシステムとロードマップ

15.1 関連プロジェクト

プロジェクト説明連携方法
KEDA HTTP Add-onHTTP ベースのスケーリングHelm Add-on
Knativeサーバーレスプラットフォーム代替/補完
Argo Eventsイベント駆動ワークフロー連携可能
Prometheusメトリクス監視スケーラー + 監視
cert-manager証明書管理TLS 証明書自動更新
External Secrets Operatorシークレット管理認証情報の外部管理

15.2 KEDA のロードマップと今後の方向性

KEDA プロジェクトは以下の方向性で進化を続けている:

  1. スケーラーの拡充: 新しいイベントソースへの対応を継続的に追加
  2. パフォーマンス改善: 大規模環境でのスケーリング性能の向上
  3. セキュリティ強化: Pod Identity、OPA 連携などのセキュリティ機能
  4. 可観測性の向上: OpenTelemetry 対応、トレーシング
  5. マルチクラスタ: クラスタ間のスケーリング連携
  6. AI/ML ワークロード: GPU リソースのイベント駆動スケーリング

15.3 コミュニティとサポート

  • GitHub: https://github.com/kedacore/keda
  • ドキュメント: https://keda.sh
  • Slack: CNCF Slack の #keda チャンネル
  • Monthly Community Meeting: 定期的なコミュニティミーティング
  • CNCF ステータス: Graduated(最高レベルの成熟度)

まとめ

KEDA は Kubernetes のオートスケーリング機能を大幅に拡張し、イベント駆動型のゼロからNへのスケーリングを実現するプロジェクトである。CNCF Graduated プロジェクトとして認定されており、プロダクション環境での使用に十分な成熟度を持つ。

主なメリット:

  • コスト最適化: ゼロスケーリングによりアイドル時のリソースコストを削減
  • 柔軟性: 60以上のスケーラーで多様なイベントソースに対応
  • 標準準拠: Kubernetes HPA を拡張する形で動作し、既存のエコシステムと互換
  • 運用性: Prometheus メトリクス、Fallback、Pause/Resume など運用に必要な機能を搭載

SRE エンジニアにとって、KEDA はマイクロサービスアーキテクチャのスケーリング戦略を根本的に改善するツールである。適切な設計と運用により、コスト効率と可用性を両立したスケーリングを実現できる。