Horizontal Pod Scalerとは
Horizontal Pod Scaler(以降HPA)とはPodのCPU使用の負荷に応じて、どの程度Podをスケールイン/アウトをするかを定義する機能です。
HPAのマニフェストの定義において、Deploymentに対して命令を送り、Replica数を制御します。
以下のマニフェストファイルを例に解説していきます。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: aws-hpa
namespace: aws-01
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: aws-auth-internal
minReplicas: 1
maxReplicas: 3
metrics:
- type: ContainerResource
containerResource:
container: aws-auth-internal
name: cpu
target:
type: Utilization
averageUtilization: 90
- type: ContainerResource
containerResource:
container: aws-auth-internal
name: memory
target:
type: Utilization
averageUtilization: 90
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Pods
value: 1
periodSeconds: 300
scaleDown:
stabilizationWindowSeconds: 3600
policies:
- type: Pods
value: 1
periodSeconds: 300
spec.scaleTargetRef
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment # スケーリング対象のリソース種類
name: aws-auth-internal # スケーリング対象のDeployment名
minReplicas: 1 # 最小レプリカ数
maxReplicas: 3 # 最大レプリカ数
spec.scaleTargetRef
において、スケーリング対象のリソースを指定します。
-
kind: Deployment
-> スケールする対象にDeployment
を指定しています -
name: aws-auth-internal
-> スケーリング対象のDeployment
名を指定いています。ここで指定したDeployment
名とDeployment
のマニフェストファイルのmetadata.name
の名称と一致させる必要があります -
minReplicas: 1
-> 最小のレプリカ数を指定 -
maxReplicas: 3
-> 最大のレプリカ数を指定
spec.metrics
metrics:
- type: ContainerResource # コンテナのリソース使用率を監視
containerResource:
container: aws-auth-internal # 監視対象のコンテナ名
name: cpu # 監視するリソース = CPU
target:
type: Utilization # 使用率
averageUtilization: 90 # 使用率90%以上
spec.metrics
においてHPAがスケーリングの判断に使用するメトリクスを定義しています。
-
type: ContainerResource
-> コンテナのリソース使用率を監視することを定義しています -
container: aws-auth-internal
-> 監視対象のコンテナ名を指定しています。ここで指定したコンテナ名はDeployment
で指定するspec.containers.name
の名称と一致する必要があります -
name: cpu
-> 監視するリソースがCPUであることを示しています -
type: Utilization
-> 監視するCPUの使用率を基準にスケーリングします -
averageUtilization: 90
-> CPU使用率の具体的な数字を定義しています。この場合90%を超えるとスケールアウトします。
- type: ContainerResource
containerResource:
container: aws-auth-internal
name: memory # 監視するリソース = メモリ
target:
type: Utilization
averageUtilization: 90
リスト形式で監視するリソースの対象を複数指定します。
name: memory
とすることでメモリ使用率が90%以上の場合にスケールアウトする定義をしています。
spec.behavior
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # 即時反映
policies:
- type: Pods
value: 1 # 1Podずつ増加
periodSeconds: 300
scaleDown:
stabilizationWindowSeconds: 3600
policies:
- type: Pods
value: 1
periodSeconds: 300
spec.behavior
においてスケールする挙動を定義しています。
scaleupの挙動
具体的な挙動は、メトリクスが90%を超えた場合に、stabilizationWindowSeconds: 0
と定義しているため即時にスケールアウトが開始します。
-
value: 1
-> Podが1つ追加されます -
periodSeconds: 300
-> 90%超過が300秒、つまり5分間続けば1つPodを追加します(ただし、spec.scaleTargetRef
で定義している通りmaxReplicas: 3
までです)
- 時刻 00:00: CPU使用率が95% → Podが1つ増え 2つに。
- 時刻 00:05: まだ90%超え → さらに1Pod増え 3つに(maxReplicas到達)。
- 時刻 00:10: 3Podでも90%超えていても、これ以上増やせない(maxReplicas制限)。
scaleDownの挙動
具体的な挙動はメトリクスが継続的に90%を下回っている場合にスケールインをします。
継続的とはstabilizationWindowSeconds: 3600
でメトリクスが90%を下回ってから一時的な負荷低下でスケールインすることを防ぐために3600秒、つまり1時間は様子を見るという意味になります。
1時間以内に90%を超えることがなければ、Podを一つ削除します。
そこからさらにperiodSeconds: 300
で5分間隔でPodを一つ削除します。
- 時刻 00:00: CPU使用率が95% -> Podが増える (Podが2つ)
- 時刻 00:05: まだ90%超え → さらに1Pod増え 3つに
- 時刻 01:05: CPU使用率が60% -> スケールインを検知開始しここから1時間メトリクスの状況を監視
- 時刻 02:05: CPU使用率が60% -> Podが1つ削除 (Podが2つ)
- 時刻 02:10: CPU使用率が60% -> Podが1つ削除 (Podが1つ
minReplicas: 1
の上限となりこれ以下とはならない)
KubernetesのHPAマニフェストにおけるスケールアップ/スケールダウンの言葉の意味はAWSなどで使用されるスケールアップ/スケールダウンの意味とは異なります。
マニフェスト上ではscaleUp
とscaleDown
と記載しておりますが、実際にはスケールアウト = Podを増やすこと、スケールイン = Podを減らすことの意味です。
検証
ローカルkindクラスター上でDeployment, HPAをapplyして動作検証してみます。
前提としてメトリクスを収集するためにmetrics-server
が必要となるめ、metrics-server
のインストールから実施していきます。
kindのクラスターは構築できている前提でお話します。
環境はWindowsのWSL2の環境で実行していきます。
metrics-serverの構築
以下コマンドでmetrics-server
をapplyします。
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
# metrics-serverがkubeletとのTLS証明書検証をスキップする
# このコマンドを実行しておかないとmetrics-serverが正常に起動しない
kubectl patch -n kube-system deployment metrics-server --type=json \
-p '[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
# metrics-serverが正常に起動しているかの確認
kubectl get pods -n kube-system -l k8s-app=metrics-server
NAME READY STATUS RESTARTS AGE
metrics-server-598746d78d-kf7nw 1/1 Running 0 49s
以下Deployment.yamlをapply
します。
以下yamlは0.1CPUを最低限保証するリソースとしてPodに割り当てます。
またlimits
で0.2CPUを上限として設定することで、Podがこの制限を超えてCPUを使用することを制限します。
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cpu-load-generator
labels:
app: cpu-load-generator
spec:
replicas: 1
selector:
matchLabels:
app: cpu-load-generator
template:
metadata:
labels:
app: cpu-load-generator
spec:
containers:
- name: busybox
image: busybox
resources:
requests:
cpu: "100m" # 0.1 CPUコアをリクエスト
limits:
cpu: "200m" # 0.2 CPUコアが上限
command: ["sh", "-c"]
args:
- while true; do echo 'Generating CPU load...'; timeout 0.5 sha256sum /dev/zero; sleep 0.5; done
STATUSがRunningになっていればOKです。
kubectl apply -f deployment.yaml
deployment.apps/cpu-load-generator created
kubectl get pods -w
NAME READY STATUS RESTARTS AGE
cpu-load-generator-6897fdd78f-qpjxq 1/1 Running 0 73s
以下のhpa.yamlをapply
します。
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-demo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: cpu-load-generator # Deploymentの名前と一致させる
minReplicas: 1
maxReplicas: 5
metrics:
- type: ContainerResource
containerResource:
container: busybox # Deploymentのコンテナ名と一致
name: cpu
target:
type: Utilization
averageUtilization: 50 # CPU使用率50%でスケール
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Pods
value: 1
periodSeconds: 30 # 30秒ごとに1Pod増加
scaleDown:
stabilizationWindowSeconds: 60 # 1分待機後に削除
policies:
- type: Pods
value: 1
periodSeconds: 30 # 30秒ごとに1Pod削除
HPAをapply
します。
kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/hpa-demo created
以下コマンドでPodのスケール状況を確認してみます。
kubectl get hpa hpa-demo -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 1 17s
hpa-demo Deployment/cpu-load-generator 117%/50% 1 5 2 31s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 2 46s
hpa-demo Deployment/cpu-load-generator 116%/50% 1 5 3 61s
hpa-demo Deployment/cpu-load-generator 113%/50% 1 5 3 76s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 4 92s
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 4 107s
hpa-demo Deployment/cpu-load-generator 112%/50% 1 5 5 2m2s
hpa-demo Deployment/cpu-load-generator 114%/50% 1 5 5 2m32s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 5 2m48s
hpa-demo Deployment/cpu-load-generator 116%/50% 1 5 5 3m3s
hpa-demo Deployment/cpu-load-generator 113%/50% 1 5 5 3m18s
上記の結果から、hpa.yamlで定義した通りの動作になっているのがわかります。
apply直後からCPU使用率が閾値50%に対して118%と大幅に超過しています。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 1 17s
applyから30秒経過後、CPU使用率117%と超過しており、Pod数が1 -> 2に増加しています
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 1 17s
hpa-demo Deployment/cpu-load-generator 117%/50% 1 5 2 31s
さらに30秒経過後、CPU利用率116%と超過しており、Pod数が 2 -> 3へ増加しています。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 1 17s
hpa-demo Deployment/cpu-load-generator 117%/50% 1 5 2 31s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 2 46s
hpa-demo Deployment/cpu-load-generator 116%/50% 1 5 3 61s
以降最終的にPod数が最大数の5つまでスケールアウトしていることがわかります。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 1 17s
hpa-demo Deployment/cpu-load-generator 117%/50% 1 5 2 31s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 2 46s
hpa-demo Deployment/cpu-load-generator 116%/50% 1 5 3 61s
hpa-demo Deployment/cpu-load-generator 113%/50% 1 5 3 76s
hpa-demo Deployment/cpu-load-generator 115%/50% 1 5 4 92s
hpa-demo Deployment/cpu-load-generator 118%/50% 1 5 4 107s
hpa-demo Deployment/cpu-load-generator 112%/50% 1 5 5 2m2s
それでは逆にスケールインの動作確認をしてみます。
以下コマンドでPodが5つ起動していることを確認します。
kubectl get hpa hpa-demo; kubectl get pods -l app=cpu-load-generator
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 113%/50% 1 5 5 23m
NAME READY STATUS RESTARTS AGE
cpu-load-generator-6897fdd78f-2mkr5 1/1 Running 0 23m
cpu-load-generator-6897fdd78f-78scs 1/1 Running 0 22m
cpu-load-generator-6897fdd78f-nbv7d 1/1 Running 0 22m
cpu-load-generator-6897fdd78f-qpjxq 1/1 Running 0 70m
cpu-load-generator-6897fdd78f-qslsj 1/1 Running 0 21m
以下コマンドでdeploymentの負荷設定を編集します。
kubectl edit deployment cpu-load-generator
以下の-argsの値を変更します。
# 変更前
spec:
containers:
- args:
- while true; do echo 'Generating CPU load...'; timeout 0.5 sha256sum /dev/zero;
sleep 5
で5秒間プロセスが完全停止するループを実行するため、CPU使用率を極小にします。
# 変更後
spec:
containers:
- args:
- while true; do echo 'Low CPU load'; sleep 5; done
以下コマンドでスケールインする遷移を確認してみましょう。
kubectl get hpa hpa-demo -w
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 114%/50% 1 5 5 32m
hpa-demo Deployment/cpu-load-generator 114%/50% 1 5 5 32m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 5 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 4 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 4 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 3 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 3 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 2 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 2 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 1 34m
最初のスケールインでは1分待機後にPodを削除する動きをする想定ですが、
CPU使用率が32m時点ではまだ114%でそこから1分後の33mに1%まで負荷が低下し、Pod数が5 -> 4に減少しているがわかります。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-demo Deployment/cpu-load-generator 114%/50% 1 5 5 32m
hpa-demo Deployment/cpu-load-generator 114%/50% 1 5 5 32m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 5 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 4 33m
以降m
表記で少しわかりづらいですが、1分経過せずにPodが1つずつ減少していっているのがわかります。
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 4 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 4 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 3 33m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 3 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 2 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 2 34m
hpa-demo Deployment/cpu-load-generator 1%/50% 1 5 1 34m
マニフェストの想定通りに検証ができましたので最後に後片付けをします。
以下コマンドでHPAとDeploymentを削除します。
kubectl delete hpa hpa-demo
horizontalpodautoscaler.autoscaling "hpa-demo" deleted
kubectl delete deployment cpu-load-generator
deployment.apps "cpu-load-generator" deleted
# 削除されていることの確認
kubectl get hpa,deploy -l app=cpu-load-generator
No resources found in default namespace.