KEDA
KEDA(Kubernetes-based Event Driven Autoscaler)包括的技術ガイド
目次
- KEDA とは何か
- なぜ KEDA が必要なのか ─ HPA の限界
- 主要機能と特徴
- HPA / VPA / KEDA の比較
- アーキテクチャ詳解
- CRD リファレンス
- スケーラーカタログ
- 高度な機能
- インストールと構成
- モニタリングとオブザーバビリティ
- トラブルシューティング
- 実践的ユースケース
- セキュリティとベストプラクティス
- パフォーマンスチューニング
- エコシステムとロードマップ
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 機能比較表
| 機能/特性 | HPA | VPA | KEDA |
|---|---|---|---|
| スケーリング方向 | 水平(Pod 数) | 垂直(リソース量) | 水平(Pod 数) + Job |
| メトリクスソース | CPU/メモリ/カスタム | CPU/メモリ | 60+ 外部ソース |
| ゼロスケーリング | 不可(min=1) | 不可 | 可能(min=0) |
| イベント駆動 | 限定的 | 非対応 | ネイティブ対応 |
| Job スケーリング | 非対応 | 非対応 | ScaledJob で対応 |
| 複合メトリクス | 基本的 | 非対応 | Scaling Modifiers |
| CRD 必要 | なし(組み込み) | あり | あり |
| CNCF ステータス | Kubernetes 組み込み | Sandbox | Graduated |
| スケーリング速度 | 中速 | 低速(再起動) | 高速(ポーリング間隔) |
| 学習コスト | 低 | 低 | 中 |
| 運用コスト | 低 | 低 | 中 |
4.2 使い分けガイドライン
┌────────────────────────────────┐
│ ワークロードの特性は? │
└───────────────┬────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
v v v
CPU/メモリ イベント駆動 リソース最適化
ベースの スケーリング (Pod サイズ)
スケーリング が必要 が必要
│ │ │
v v v
┌──┴──┐ ┌────┴────┐ ┌──┴──┐
│ HPA │ │ KEDA │ │ VPA │
└─────┘ └─────────┘ └─────┘
│
┌──────┴──────┐
│ │
v v
長期実行 バッチ/ジョブ
ワークロード ワークロード
│ │
v v
ScaledObject ScaledJob
推奨される組み合わせ:
- KEDA + VPA: KEDA でイベント駆動の水平スケーリング、VPA で各 Pod のリソース最適化
- HPA + VPA: 標準的なウェブアプリケーション(異なるメトリクスで併用)
- 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 は以下の責務を持つ:
- 0→1 スケーリング: イベントソースをポーリングし、イベントが検出されたら Deployment のレプリカ数を 0 から 1 に変更する
- 1→0 スケーリング: イベントが一定期間検出されない場合、レプリカ数を 1 から 0 に変更する(
cooldownPeriodに基づく) - HPA の自動管理: ScaledObject が作成されると、対応する HPA を自動的に生成・管理する
- 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 # 最大レプリカ数
ポーリングの動作:
pollingIntervalごとに各スケーラーのIsActive()とGetMetrics()を呼び出すIsActive()がfalse→ ゼロスケールの候補IsActive()がtrue→ メトリクスを HPA に提供- 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
idleReplicaCount と minReplicaCount の違い:
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 Kafka | Consumer Group のラグに基づくスケーリング |
| AWS SQS | キューの深さに基づくスケーリング |
| AWS Kinesis | シャードあたりのメッセージ数 |
| Azure Service Bus | メッセージ数/アクティブメッセージ数 |
| Azure Event Hubs | Consumer Group のラグ |
| Google Pub/Sub | 未確認メッセージ数 |
| RabbitMQ | キューの深さ/メッセージレート |
| NATS JetStream | ストリームの未処理メッセージ |
| Redis Streams | Pending メッセージ数 |
| ActiveMQ | キューのメッセージ数 |
| IBM MQ | キューの深さ |
| Solace PubSub+ | メッセージ数 |
| Pulsar | バックログメッセージ数 |
データベース
| スケーラー | 説明 |
|---|---|
| PostgreSQL | クエリ結果に基づくスケーリング |
| MySQL | クエリ結果に基づくスケーリング |
| MongoDB | クエリ結果に基づくスケーリング |
| MSSQL | クエリ結果に基づくスケーリング |
| Cassandra | クエリ結果に基づくスケーリング |
| CouchDB | 保留中の変更数 |
| Elasticsearch | クエリ結果に基づくスケーリング |
| InfluxDB | クエリ結果に基づくスケーリング |
| Etcd | キーの値に基づくスケーリング |
メトリクス / 監視
| スケーラー | 説明 |
|---|---|
| Prometheus | PromQL クエリ結果に基づくスケーリング |
| Datadog | メトリクスクエリに基づくスケーリング |
| New Relic | NRQL クエリに基づくスケーリング |
| Dynatrace | メトリクスに基づくスケーリング |
| Graphite | クエリに基づくスケーリング |
| Metrics API | 任意のメトリクスエンドポイント |
クラウドサービス
| スケーラー | 説明 |
|---|---|
| AWS CloudWatch | CloudWatch メトリクスに基づくスケーリング |
| Azure Monitor | Azure Monitor メトリクス |
| Azure Log Analytics | ログクエリ結果 |
| GCP Stackdriver | Stackdriver メトリクス |
| GCP Cloud Tasks | タスク数 |
その他
| スケーラー | 説明 |
|---|---|
| Cron | 時間ベースのスケーリング |
| CPU / Memory | リソースベース(HPA 互換) |
| External | gRPC 外部スケーラー |
| Kubernetes Workload | 他のワークロードのレプリカ数に基づく |
| Selenium Grid | Selenium テストキュー |
| GitHub Runner | ワークフローキュー |
| Loki | LogQL クエリ結果 |
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 アノテーションを設定すると:
- KEDA はスケーリングを停止する
- レプリカ数が指定値に固定される
- HPA は無効化される
- アノテーションを削除すると通常のスケーリングが再開される
ユースケース:
- デプロイ中のスケーリング停止
- トラブルシューティング中の状態固定
- メンテナンスウィンドウでの制御
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
注意点:
- フォールバックは
minReplicaCountとmaxReplicaCountの範囲内で適用される 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_ready | Gauge | ScaledObject の準備状態 |
keda_scaledobject_paused | Gauge | ScaledObject の一時停止状態 |
keda_scaled_object_errors | Counter | ScaledObject のエラー数 |
keda_scaledjob_ready | Gauge | ScaledJob の準備状態 |
keda_trigger_totals | Gauge | 登録されたトリガーの総数 |
keda_internal_scale_loop_latency | Histogram | スケーリングループの遅延 |
keda_resource_totals | Gauge | KEDA リソースの総数 |
keda_build_info | Gauge | ビルド情報 |
Metrics Server メトリクス
| メトリクス | タイプ | 説明 |
|---|---|---|
keda_scaler_active | Gauge | スケーラーのアクティブ状態 |
keda_scaler_metrics_value | Gauge | スケーラーの現在のメトリクス値 |
keda_scaler_metrics_latency | Histogram | メトリクス取得の遅延 |
keda_scaler_errors | Counter | スケーラーのエラー数 |
keda_scaler_errors_total | Counter | スケーラーのエラー総数 |
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 metric | Metrics API のエラー | Metrics Server のログを確認 |
target not found | ターゲットリソースが存在しない | Deployment/StatefulSet の名前を確認 |
permission denied | RBAC 権限不足 | ServiceAccount と Role を確認 |
certificate signed by unknown authority | TLS 証明書の問題 | 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 │ │
│ └───────────┘ │ │ └───────────┘ │
└─────────────────┘ └─────────────────┘
マルチクラスタでの注意点:
- イベントソースの共有: 複数クラスタが同じ Kafka/SQS を参照する場合、Consumer Group の設計が重要
- スケーリングの競合: 各クラスタが独立にスケーリングするため、全体のキャパシティ管理が必要
- フェイルオーバー: プライマリクラスタ障害時に DR クラスタが自動的にスケールアップ
- メトリクスの集約: 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 一般的なベストプラクティス
- 名前空間分離: KEDA コンポーネントは専用の名前空間(
keda)にデプロイする - リソース制限: Operator と Metrics Server にリソースリクエスト/リミットを設定する
- 高可用性: プロダクションでは Operator と Metrics Server を各2レプリカ以上にする
- 監視: Prometheus メトリクスとアラートを設定する
- バージョン管理: KEDA のバージョンを固定し、計画的にアップグレードする
- テスト: ステージング環境でスケーリング動作をテストしてからプロダクションに適用する
- Fallback 設定: 重要なワークロードには必ず Fallback を設定する
- cooldownPeriod: ワークロード特性に応じて適切な値を設定する(頻繁なスケーリングの回避)
- maxReplicaCount: 必ず上限を設定し、暴走を防止する
- ログレベル: 通常は
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-on | HTTP ベースのスケーリング | Helm Add-on |
| Knative | サーバーレスプラットフォーム | 代替/補完 |
| Argo Events | イベント駆動ワークフロー | 連携可能 |
| Prometheus | メトリクス監視 | スケーラー + 監視 |
| cert-manager | 証明書管理 | TLS 証明書自動更新 |
| External Secrets Operator | シークレット管理 | 認証情報の外部管理 |
15.2 KEDA のロードマップと今後の方向性
KEDA プロジェクトは以下の方向性で進化を続けている:
- スケーラーの拡充: 新しいイベントソースへの対応を継続的に追加
- パフォーマンス改善: 大規模環境でのスケーリング性能の向上
- セキュリティ強化: Pod Identity、OPA 連携などのセキュリティ機能
- 可観測性の向上: OpenTelemetry 対応、トレーシング
- マルチクラスタ: クラスタ間のスケーリング連携
- 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 はマイクロサービスアーキテクチャのスケーリング戦略を根本的に改善するツールである。適切な設計と運用により、コスト効率と可用性を両立したスケーリングを実現できる。