PodのHorizontal Pod Autoscaling(水平podオートスケーリング)
podのHorizontal pod autoscaling(水平podオートスケーリング)とは、podの負荷に応じて自動的にpodの数を増減させることを指す。
HorizontalPodAutoscaler
リソースを定義することで水平オートスケーリングが可能になる。
まずDeployment, ReplicaSet, ReplicationController, StatefulSetはscaled resource object
と呼ばれる。
これらがauto scalingが可能なリソース。
HorizontalPodAutoscaler
リソースの定義例:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: php-hpa
namespace: default
spec:
scaleTargetRef: # ここでautoscale対象となる`scaled resource object`を指定
apiVersion: apps/v1
kind: Deployment
name: php-deploy
minReplicas: 1 # 最小レプリカ数
maxReplicas: 5 # 最大レプリカ数
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50 # CPU使用率が常に50%になるように指定
autoscalingプロセスは以下の3つで行われる。
- 指定したscaled resource objectによって管理されている全てのpodのメトリックを取得する
- メトリックを定義されたターゲット値に近づけるためにはどのくらいのpodが必要か計算する
- scaled resource objectのreplicas fieldを更新する。
ポイントとしては、auto scalingはtarget valueに近づくようにpod数が調整されるということ。
target valueが80なら 全体(全podの合計)のCPU使用率が80%になるように調整される。たとえば全体のCPU使用率が90%ならpod数は増えるし、50%ならpod数は減らされる。
スケールアウトのための計算方法は以下 (詳しくは[Autoscaling Algorithm] (https://github.com/kubernetes/community/blob/master/contributors/design-proposals/autoscaling/horizontal-pod-autoscaler.md#autoscaling-algorithm)を参照)
必要なレプリカ数 = ceil(sum(Podの現在のCPU使用率) / targetAverageUtilization)
重要な点は、定期的(30秒に1回)にメトリックの取得をしているため、すぐにはスケーリングが行われないということ。少し時間がかかる。
- スケールアウト(pod数を増やす)イベントは3分おきに発生する。
- スケールイン(pod数を減らす)イベントは5分おきに発生する。
例
オートスケールされやすいようにCPUを100%使うようなpodを作成する
$ cat hpa-test-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-test-deploy
spec:
replicas: 3
template:
metadata:
name: hpa-app
labels:
app: hpa-app
spec:
containers:
- image: busybox
command: ["dd", "if=/dev/zero", "of=/dev/null"] # CPUを100%使うように
$ kubectl apply -f hpa-test-deploy.yaml
deployment "hpa-test-deploy" created
3つpodができていることを確認
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hpa-test-deploy-69487b74dc-bfk6s 1/1 Running 0 9s
hpa-test-deploy-69487b74dc-rc4k2 1/1 Running 0 9s
hpa-test-deploy-69487b74dc-zs2j7 1/1 Running 0 9s
しばらくするとtopコマンドでメトリックスが取得可能状態になる
$ kubectl top pod
NAME CPU(cores) MEMORY(bytes)
hpa-test-deploy-69487b74dc-rc4k2 945m 0Mi
hpa-test-deploy-69487b74dc-zs2j7 957m 0Mi
hpa-test-deploy-69487b74dc-bfk6s 950m 0Mi
CPU使用率を50%に保つHorizontalPodAutoscalerリソースを作る
$ cat hpa-test.yaml
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: hpa-test
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hpa-test-deploy
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 50
$ kubectl apply -f hpa-test.yaml
horizontalpodautoscaler "hpa-test" created
すぐにはメトリックスを取得しないので最初はTARGETSの左がになる
$ kubectl get HorizontalPodAutoscaler hpa-test
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-test Deployment/hpa-test-deploy <unknown> / 50% 1 5 0 27s
しばらくするとTARGETSの左にメトリックスが表示される
$ kubectl get HorizontalPodAutoscaler hpa-test
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpa-test Deployment/hpa-test-deploy 966% / 50% 1 5 3 30s
describeしてみると、Events欄にSuccessfulRescaleと表示され、pod数が5つになったことが分かる
$ kubectl describe HorizontalPodAutoscaler hpa-test
Name: hpa-test
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"autoscaling/v2beta1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{},"name":"hpa-test","namespace":"default"},"spec":{"max...
CreationTimestamp: Fri, 20 Apr 2018 22:38:53 +0900
Reference: Deployment/hpa-test-deploy
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 966% (966m) / 50%
Min replicas: 1
Max replicas: 5
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True SucceededRescale the HPA controller was able to update the target scale to 5
ScalingActive True ValidMetricFound the HPA was able to succesfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited True TooManyReplicas the desired replica count was more than the maximum replica count
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 3s horizontal-pod-autoscaler New size: 5; reason: cpu resource utilization (percentage of request) above target
podの数を見てみると5つ(HorizontalPodAutoscalerで指定したMAXのpod replica数)になっていることが分かる
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hpa-test-deploy-69487b74dc-6sp7l 1/1 Running 0 10s
hpa-test-deploy-69487b74dc-bfk6s 1/1 Running 0 2m
hpa-test-deploy-69487b74dc-d69mt 1/1 Running 0 10s
hpa-test-deploy-69487b74dc-rc4k2 1/1 Running 0 2m
hpa-test-deploy-69487b74dc-zs2j7 1/1 Running 0 2m
他のメトリックスによるAuto Scaling
custom metrics
を用いてCPUメトリックス以外のメトリックスでオートスケーリングを行うことができる。
HorizontalPodAutoscaler
リソースには以下の4種類を指定することができる。
- Resource
- Resource Requests, Resource Limitsのようなメトリックス
- Pods
- Podのメトリックス。例えばQueries Per Second(QPS) や message broker’s queueやコネクションの数。
- Object
- Podとは直接関係ないメトリックス。たとえばIngressのHit/sやlatency。
- External
* Kubernetes外のメトリックス(例: LBのQPS、Cloud Pus/Subの溜まっているメッセージ数)
どんなメトリックスがAuto Scalingに適しているか判断する
- podのメモリ消費量はオートスケーリングメトリックスに向かない。
podが増えるほど全体のメモリ消費量は増え、使えるメモリ量が逆に減るからだ。 - メトリックスの一つとして、Queries per Second (QPS)がある。(※Requests per Secondと同義か?)
- オートスケーリングメトリックスとして
custom metrics
を使う前に、podが増減したらそのメトリックスがどのように振る舞うかよく考えること。
PodのVertical Pod Autoscaling(垂直podオートスケーリング)
Vertical Pod Autoscalerは、コンテナに割り当てるCPU、メモリのリソースの割り当てを自動的にスケールさせるリソースです。
必要とするリソース(CPU、メモリ)量があらかじめ推測しにくいアプリケーションに対して、実績に基づいてそれらしい値を決めたい場合に効果を発揮します。
猫でもわかる Vertical Pod Autoscaler がわかりやすいです。
Nodeの水平オートスケーリング
Kubernetesは、cloud providerが提供していれば、nodeのauto scalingもでき、Cluster Autoscalerという機能が担っている。
Cluster Autoscalerは、リソースが枯渇して既存のnodeにpodがschedulingできない場合に、nodeを追加する。
またリソース負荷が低いならnodeの削除も行う。
Cluster Autoscalerはnodeを追加する前にそのnodeにpodがscheduleできるかを確認する。じゃないとnodeを追加してもpodがscheduleできない事態になってしまう。
nodeを削除するとき(scale downするとき)system podsが実行されているかチェックし、されているならnodeの削除を行わない。ただしsystem podsがDaemonSetの場合を除く。DaemonSetは各nodeで実行されているためnodeからpodを削除しても問題ないため。
また unmanaged pod(replicasetやdeploymentによって管理されていないpod)やlocal storageを使っているpodが存在する場合もnodeを削除しない。
nodeを削除するさいには、nodeにunschedulableを設定する。これによりpodがscheduleされなくなる。
そしてnode上のpodが追い出される。
追い出されたpodはreplicasetやdeploymentの管理下なので他のnodeへ再scheduleされる。
Tips
-
kubectl cordon <node>
でnodeにunschedulableを設定できる。unschedulableが設定されたnodeにはpodがscheduleされなくなる。 -
kubectl drain <node>
でnodeにunschedulableを設定し、node上のpodを追い出す。 -
kubectl uncordon <node>
を実行すればnodeのunschedulableを解除できる。
cluster scale down時にサービスの中断を抑える
nodeが突然死んだ場合はどうしようもないが、手動もしくはCluster Autoscalerでnodeの削除が行われる場合は、サービスを中断させないことができる。
PodDisruptionBudget
リソースを作成すればよい。
参考: https://qiita.com/tkusumi/items/946b0f31931d21a78058
「PodDisruptionBudget
とは Node を計画的に停止したい場合に、Pod の状況を見ながら退去 (evict) させる機能です」
まとめ
- podの水平スケーリング(scale out)はHorizontalPodAutoscalerリソースを作成し、それをDeployment, ReplicaSetに指定し、対象CPU使用量を指定することで簡単にできる。
- podのCPU使用量の他に、アプリケーションが提供するcustom metricsやclusterにdeployされている他のリソースのmetricsをもとにオートスケーリングすることができる。
- (cloud providerから提供されていれば)cluster nodeもオートスケーリングできる。
参考
- Kubernetes in Action (最高に分かりやすく書かれているのでぜひ買いましょう)
- Horizontal Pod Autoscaler
- Horizontal Pod Autoscaler Walkthrough