KEDA (Kubernetes Event-driven Autoscaling) で Prometheus のメトリクスや時間ベースのスケーリングを行う

kubernetesprometheus

KEDA は Kubernetes でイベントドリブンなスケーリングを行えるようにするコンポーネントで、HorizontalPodAutoscaler とともにはたらく。CPU のほか Prometheus や Cron など様々なイベントソースの Scaler が提供されており、それをもとに HPA で replicas を増減させたり、0 ↔ 1 の変更を行ったりもできる。

K8s の HorizontalPodAutoscaler による replicas の更新と判定間隔、増減上限の設定 - sambaiz-net

Helm でインストールする。

cluster.addHelmChart('KedaChart', {
  chart: 'keda',
  release: 'kedacore',
  repository: 'https://kedacore.github.io/charts',
  namespace: 'keda',
  version: '2.14.2',
})

ScaledObject を作る。

apiVersion: 'keda.sh/v1alpha1'
kind: 'ScaledObject'
metadata:
  name: 'test-scaledobject'
spec:
  scaleTargetRef:
    kind: 'Deployment'
    name: 'testapp'
  minReplicaCount: 1
  maxReplicaCount: 10
  triggers:
  - type: prometheus
    metadata:
      serverAddress: 'http://kube-prometheus-stack-prometheus.prometheus.svc.cluster.local:9090'
      query: 'prometheus_http_requests_total{code="200",handler="/graph"}'
      threshold: '50'
  - type: cron
    metadata:
      timezone: Asia/Tokyo
      start: 40 22 * * *
      end: 50 22 * * *
      desiredReplicas: '10'

これを apply するとメトリクスが登録され、

$ kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/s0-prometheus?labelSelector=scaledobject.keda.sh/name=test-scaledobject" | jq
{
  "kind": "ExternalMetricValueList",
  "apiVersion": "external.metrics.k8s.io/v1beta1",
  "metadata": {},
  "items": [
    {
      "metricName": "s0-prometheus",
      "metricLabels": null,
      "timestamp": "2024-06-05T21:54:04Z",
      "value": "2"
    }
  ]
}

このメトリクスを参照する HPA が作られる。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
...
spec:
  maxReplicas: 10
  metrics:
  - external:
      metric:
        name: s0-prometheus
        selector:
          matchLabels:
            scaledobject.keda.sh/name: test-scaledobject
      target:
        averageValue: "50"
        type: AverageValue
    type: External
  - external:
	    metric:
	      name: s1-cron-Asia-Tokyo-4022xxx-5022xxx
	      selector:
	        matchLabels:
	          scaledobject.keda.sh/name: test-scaledobject
	    target:
	      averageValue: "1"
	      type: AverageValue
	  type: External
  minReplicas: 1
  ...

既に HPA がある場合エラーになるが、scaledobject.keda.sh/transfer-hpa-ownership: true annotation を付けることで ScaledObject の管理に移行できる。

metadata:
  annotations:
    scaledobject.keda.sh/transfer-hpa-ownership: "true"
spec:
  ...
  advanced:
    horizontalPodAutoscalerConfig:
      name: testapp-hpa

Cron の期間中に replicas が desiredReplicas まで増えることが 確認できた。

Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  15m   horizontal-pod-autoscaler  New size: 4; reason: external metric s1-cron-Asia-Tokyo-4022xxx-5022xxx(&LabelSelector{MatchLabels:map[string[]string{scaledobject.keda.sh/name: test-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal  SuccessfulRescale  14m   horizontal-pod-autoscaler  New size: 8; reason: external metric s1-cron-Asia-Tokyo-4022xxx-5022xxx(&LabelSelector{MatchLabels:map[string[]string{scaledobject.keda.sh/name: test-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal  SuccessfulRescale  14m   horizontal-pod-autoscaler  New size: 10; reason: external metric s1-cron-Asia-Tokyo-4022xxx-5022xxx(&LabelSelector{MatchLabels:map[string[]string{scaledobject.keda.sh/name: test-scaledobject,},MatchExpressions:[]LabelSelectorRequirement{},}) above target
  Normal  SuccessfulRescale  39s   horizontal-pod-autoscaler  New size: 1; reason: All metrics below target

参考

KEDAによるKubernetesのイベントドリブンなスケーリングの実践|hayajo

Prometheusメトリクスに基づいて Kubernetes Pod をオートスケーリングさせてみた - QG Tech Blog