Prometheus × KEDA:動的ワーカーの「影」を支配するオブザーバビリティの極致
大規模なバッチ処理やイベント駆動型のワークロードをKubernetesで運用している諸君なら、一度は「消えゆくターゲット」の呪縛に苦しんだことがあるはずだ。
静的な設定ファイル(`prometheus.yaml`)に依存したスクレイピングは、もはやレガシーの遺物である。ワーカーがスパイクし、処理を終えて消失する。その一瞬の隙間を埋め、メトリクスの連続性を維持しなければ、オブザーバビリティは瓦解する。
今日は、KEDAとPrometheusを高度に結合し、動的に生成されるPodを「自動認識」させるだけでなく、オートスケーリングのトリガーそのものをPrometheusのメトリクスで統制する、真のクローズドループ・アーキテクチャについて深淵を覗く。
—
1. 課題の本質:監視対象の「死」と「生」の非同期性
Prometheusのデフォルト設定(static_config)は、動的なPodの増減には無力だ。`kubernetes_sd_configs`を使えば自動検知は可能だが、大規模なクラスタでは「サービスディスカバリのオーバーヘッド」が無視できない。
特に、数千のPodが短寿命で乱舞するバッチ環境では、Prometheusのメモリを食い潰すのはターゲットのメタデータ管理だ。我々が構築すべきは、「必要な時に、必要なターゲットだけを監視し、負荷を平滑化する」洗練されたパイプラインである。
—
2. アーキテクチャの真髄:KEDAによる「監視の連鎖」
単なるオートスケーリングではない。Prometheusのクエリ結果をトリガーにKEDAがPodを増減させ、そのPodをPrometheusが即座にスクレイピング対象として取り込む。この「相互依存関係」を設計する。
KEDA ScaledObject による動的制御
KEDAを使用して、Prometheusのメトリクスに基づいたスケーリングを定義する。ここでは「キューの深さ」や「ワーカーの処理待ち時間」ではなく、「メトリクスの欠落そのもの」を検知してスケールするという高度な戦略を推奨する。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: batch-worker-scaler
spec:
scaleTargetRef:
name: worker-deployment
minReplicaCount: 1
maxReplicaCount: 100
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-service.monitoring.svc.cluster.local
metricName: worker_queue_depth # キューの長さを監視
threshold: ’50’ # 50タスク以上でスケールアウト
query: sum(worker_queue_length{job=”batch-worker”})
—
3. 実装の深淵:動的スクレイピングターゲットのハック
KEDAで生成したPodをPrometheusに自動認識させるには、`ServiceMonitor` または `PodMonitor` を活用するのが定石だ。しかし、上級者はその一歩先へ行く。
PodMonitorによるメタデータ精査
`PodMonitor`を使用して、特定のラベルを持つPodのみを動的に抽出する。ここでの鍵は、`relabel_configs`の極限活用だ。
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: worker-monitor
spec:
selector:
matchLabels:
app: dynamic-worker # KEDAで動的に増えるPodのラベル
podMetricsEndpoints:
- port: metrics
interval: 15s
# ここで不必要なラベルをドロップし、Prometheusのメモリ使用量を最適化する
relabelings:
- action: labeldrop
regex: “(pod_template_hash|controller_revision_hash)”
【エキスパートの知見】
`labeldrop`は単なる整理整頓ではない。Prometheusのインデックス効率を飛躍的に高める。不要な高カーディナリティのラベル(`pod_template_hash`等)を削除するだけで、クエリパフォーマンスは30%以上向上するケースが多い。
—
4. 運用上の致命的な注意点:オブザーバビリティの死角
この構成を採用する上で、必ず直面する「落とし穴」が2つある。
① スケーリングのハンチング問題
メトリクスの取得間隔(`scrape_interval`)と、KEDAの評価間隔(`pollingInterval`)が同期していないと、Podが生成された直後に削除される「スケーリング・フラッピング」が発生する。
- 対策: KEDAの `cooldownPeriod` を `scrape_interval` の少なくとも3倍に設定すること。
② Prometheusのメモリ爆発(高カーディナリティの罠)
動的にPodが増減すると、古いPodの時系列データが「Stale(陳腐化)」として残り続ける。
- 対策: `–storage.tsdb.min-block-duration` と `–storage.tsdb.max-block-duration` を調整し、古いターゲットのメタデータを効率的にパージする設定を必ず導入せよ。
—
5. 伝説的アーキテクトからの提言:CLIによる完全自動化
GUI操作は不要だ。CI/CDパイプラインから直接KEDAとPrometheusの構成を更新する、独自の自動化スクリプト(GoまたはPython)を実装せよ。
ターゲットの急増を事前検知し、Prometheusのスクレイピング設定を動的に調整する疑似ロジック
def optimize_scraping_frequency(current_worker_count):
if current_worker_count > 500:
# スケールが大きすぎる場合は、一時的にスクレイプ間隔を緩める
update_prometheus_scrape_interval(“30s”)
else:
update_prometheus_scrape_interval(“15s”)
システムを「監視する」のではなく、システムと「呼吸を合わせる」。これがオブザーバビリティの極致である。KEDAは単なるオートスケーラーではない。君のインフラが自律的に進化するための「神経系」なのだ。
さあ、マニュアルを閉じ、Prometheusのメモリプロファイルを開き、真のパフォーマンスの深淵を構築せよ。健闘を祈る。