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

kubernetes

HorizontalPodAutoscaler (HPA) は metrics をもとに scaleTargetRef のリソースの replicas を更新するリソース。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: testapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: testapp
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Deployment の manifest に replicas が含まれていると apply したときにその値で上書きされてしまうことがあるので含めないほうがよい。ただ、だからといって replicas を消して apply すると kubectl.kubernetes.io/last-applied-configuration との merge patch がはたらきデフォルトの 1 になってしまうことに注意が必要。

cpu などを metrics を指定する場合 Metrics Server をインストールする必要がある。

// $ kubectl top node
// error: Metrics API not available

cluster.addHelmChart('metrics-server', {
  chart: 'metrics-server',
  release: 'metrics-server',
  repository: 'https://kubernetes-sigs.github.io/metrics-server',
  namespace: 'kube-system',
  createNamespace: false,
  wait: true
})

Utilization はコンテナの合計使用量と request または limit リソース量で計算され、replicas は次の式によって決定される。例えば averageUtilization: 70 に対して平均 CPU 使用率が 140% のとき、replicas は現在の倍に設定される。

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

複数の世代のインスタンスタイプを併用していると Pod ごとの CPU の使用率にばらつきがあり平均ではうまくスケールしないことがある。その場合 KEDA などが提供する external metrics を参照することもできる。

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

ばらつきがリクエストに由来している場合 ALB のルーティングポリシーを LOR に変更するとよい。

EKSクラスタにAWS Load Balancer ControllerをインストールしてALBのIngressを立てる - sambaiz-net

複数の metrics がある場合は最大の replicas となり、エラーなどで取れないものがある場合は縮退しないようになっている。

判定間隔は kube-controller-manager の –horizontal-pod-autoscaler-sync-period で設定でき、デフォルトは 15 秒になっている。スケールを早めるためにはなるべく短くしたいところだがコントロールプレーンを触れない EKS では現状変更できない。いずれにせよリソースが足りないと Pod は起動しないので併せて PriorityClass などでリソースを確保しやすくしたりノードのスケールの高速化に取り組む必要がある。

K8s の Pod の Prirority とそれによる Preemption - sambaiz-net

CDK で EKS クラスタに Karpenter をインストールし柔軟で高速なオートスケールを行う - sambaiz-net

behavior で増減上限を設定することができデフォルトは次のような設定になっている。Percent の periodSeconds: 15 と value: 100 は 15秒間に最大で現在の pod 数の 100% 分増減することを意味する。複数の policy がある場合 selectPolicy によってどの値が適用されるかが選択され、デフォルトは Max となっている。stabilizationWindowSeconds は頻繁なメトリクスの更新によって pod 数が安定しない flapping を避けるための値で、この期間中の最大の値が採用される。

behavior:
  scaleDown:
	  stabilizationWindowSeconds: 300
	  policies:
	  - type: Percent
		  value: 100
		  periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
	  policies:
	  - type: Percent
	    value: 100
	    periodSeconds: 15
	  - type: Pods
	    value: 4
	    periodSeconds: 15
	   selectPolicy: Max

参考

あれ、本番環境のKubernetes Podがいなくなっちゃったよ