はじめに
KubernetesのHPA(Horizontal Pod Autoscaler)について、ざっくりまとめて実際に試してみたいと思います。
APIバージョンはautoscaling/v2
を想定しています。
Horizontal Pod Autoscalerとは
Horizontal Pod Autoscalerは、DeploymentやStatefulSetなどのPod数を、メトリクスをもとに自動的にスケールさせることができます。
使えるメトリクス
- リソースメトリクス(
metrics.k8s.io
)- metrics-serverから取得できるCPUやメモリなどのメトリクス
- カスタムメトリクス(
custom.metrics.k8s.io
)- メトリクスサーバーで独自に定義したメトリクス
- 外部メトリクス(
external.metrics.k8s.io
)- Kubernetes外部のメトリクス
マニフェスト
HPAのマニフェストの例は下記の通りです。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-sample
spec:
scaleTargetRef: # スケール対象
apiVersion: apps/v1
kind: Deployment
name: deployment-sample
minReplicas: 1 # 最小レプリカ数
maxReplicas: 10 # 最大レプリカ数
metrics: # スケール条件
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # CPUの利用率が50% (resource requestを100%とする)
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # スケールインするまでの待ち時間
policies:
- type: Percent # 15秒ごとに100%分のレプリカをスケールイン(最小までスケールイン)
value: 100 # 現在動いているレプリカ数を100%
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0 # スケールアウトするまでの待ち時間(0は即時)
policies:
- type: Percent # 15秒ごとに100%分のレプリカをスケールアウト
value: 100 # 現在動いているレプリカ数を100%
periodSeconds: 15
- type: Pods # 15秒ごとに4レプリカをスケールアウト
value: 4
periodSeconds: 15
selectPolicy: Max # 追加するレプリカ数が多い方を採用
レプリカ数の計算方法
必要なレプリカ数の計算方法は下記の通りです。少数は切り上げになります。
必要なレプリカ数 = 現在のレプリカ数 * ( 現在のメトリクス / ターゲットメトリクス )
試してみる
ローカルでリソースメトリクスを利用したシンプルなHPAを試してみたいと思います。
メトリクスサーバーの導入
まずはmetrics-server
を導入します。
下記からcomponents.yaml
を取得します。
Docker Desktopで導入する場合、このままではPodが起動しないので下記のcomponents.yaml
の下記の部分に--kubelet-insecure-tls
を追記します。
-- 省略 --
protocol: TCP
targetPort: https
selector:
k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls # 追記する
image: k8s.gcr.io/metrics-server/metrics-server:v0.5.2
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
-- 省略 --
metrics-server
をデプロイします。
kubectl apply -f components.yaml
下記のようにPodが実行されていれば完了です。
❯ kubectl -n kube-system get pod | grep metrics-server
metrics-server-658867cdb7-j7r8p 1/1 Running 0 4m35s
デモアプリのデプロイ
デモアプリには、下記で使われているk8s.gcr.io/hpa-example
イメージを利用します。こちらはCPU負荷の高い演算を行うイメージになっています。
deployment.yaml
は下記の通りです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
Serviceも用意します。
service.yaml
は下記の通りです。
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
アプリをデプロイします。
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
HPAの作成
次にHPAを作成します。
hpa.yaml
は下記の通りです。スケールしているのを確認したいので、スケールインとスケールアウトの設定を緩やかにしています。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 30
behavior:
scaleDown:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 50
periodSeconds: 30
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 40
periodSeconds: 30
- type: Pods
value: 2
periodSeconds: 30
selectPolicy: Max
HPAを作成します。
kubectl apply -f hpa.yaml
作成したHPAを確認すると、ターゲットのメトリクスに対して、現状のどのくらいなのかを確認できます。(現状は負荷をかけていないので0%です)
❯ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 0%/50% 1 10 1 65s
負荷をかけてみる
負荷をかけるリクエストを送り続けるPodを起動して、負荷をかけてみます。
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
HPAを確認すると、ターゲットを超えていることがわかります。
❯ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 251%/30% 1 10 1 14m
スケールアウトはすぐに反映され、レプリカ数が増えて行くのが確認できます。
❯ kubectl get deploy -w
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 12m
php-apache 1/3 1 1 14m
php-apache 2/3 3 2 14m
php-apache 3/3 3 3 14m
php-apache 3/5 3 3 15m
php-apache 3/5 5 3 15m
php-apache 4/5 5 4 15m
php-apache 5/5 5 5 15m
php-apache 5/7 5 5 16m
php-apache 5/7 7 5 16m
php-apache 6/7 7 6 16m
php-apache 7/7 7 7 16m
php-apache 7/10 7 7 17m
php-apache 7/10 10 7 17m
php-apache 8/10 10 8 17m
php-apache 9/10 10 9 17m
php-apache 10/10 10 10 17m
負荷を止めてみる
負荷をかけていたPodを停止させて、負荷を止めます。
HPAを確認するとターゲットのメトリクスが少なくなったことが確認できます。
❯ kubectl get hpa -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache-hpa Deployment/php-apache 31%/30% 1 10 10 19m
php-apache-hpa Deployment/php-apache 0%/30% 1 10 10 20m
負荷を止めてからしばらくすると、レプリカ数が減っていくことも確認できます。
❯ kubectl get deploy -w
NAME READY UP-TO-DATE AVAILABLE AGE
...
php-apache 5/5 5 5 20m
php-apache 5/2 5 5 21m
php-apache 2/2 2 2 21m
php-apache 2/1 2 2 22m
php-apache 1/1 1 1 22m
参考
- Horizontal Pod Autoscalerウォークスルー | Kubernetes
- HorizontalPodAutoscaler Walkthrough | Kubernetes
- Horizontal Pod Autoscaling | Kubernetes
- kubernetes-sigs/metrics-server: Scalable and efficient source of container resource metrics for Kubernetes built-in autoscaling pipelines.
- design-proposals-archive/monitoring_architecture.md at main · kubernetes/design-proposals-archive
- kubectl top pod responding with "Metrics not available for pod xxx" · Issue #1061 · kubernetes-sigs/metrics-server