kubernetes
HorizontalPodAutoscaler

Kubernetesのpodとnodeのauto scalingについて

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を更新する。

メトリックはHorizontalPodAutoscalerリソースによって取得されるが、HorizontalPodAutoscalerリソースはHeapsterからメトリックを取得する。HeapsterはcAdvisorからメトリックを取得する。
そのためauto scalingにはHeapsterが起動していないといけない。

ポイントとしては、auto scalingはtarget valueに近づくようにpod数が調整されるということ。
target valueが80なら 全体(全podの合計)のCPU使用率が80%になるように調整される。たとえば全体のCPU使用率が90%ならpod数は増えるし、50%ならpod数は減らされる。

※scaleoutのための計算方法は、 Autoscaling Algorithm を参照。

重要な点は、定期的にメトリックの取得をしているため、すぐにはscalingが行われないということ。少し時間がかかる。

  • scale up(pod数を増やす)イベントは3分おきに発生する。
  • scale down(pod数を減らす)イベントは5分おきに発生する。

※メモリベースのオートスケーリングはKubernetes1.8から導入された。CPUベースオートスケーリングと同じように使用できる。autoscaling/v2beta1で試せる。

オートスケールされやすいようにCPUを100%使うようなpodを作成する

$ cat hpa-test-deploy.yaml
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メトリックス以外のメトリックスでauto scalingを行うことができる。
HorizontalPodAutoscalerリソースには以下の3種類を指定することができる。

  • Resource
    • Resource Requests, Resource LimitsのようなResource Metrics
  • Pods
    • custom metricsを含むpodに関係するmetrics。 例えばQueries Per Second(QPS) や message broker’s queueの数。
  • Object
    • podとは直接関係ないmetrics。たとえばIngressのlatency。

どんなメトリックスがauto scalingに適しているか判断する

podのメモリ消費量はautoscaling metricsに向かない。
podが増えるほど全体のメモリ消費量は増え、使えるメモリ量が逆に減るからだ。
metricsの一つとして、Queries per Second (QPS)がある。
autoscaling metricsとしてcustom metricsを使う前に、podが増減したらそのmetricsがどのように振る舞うかよく考えること。

podのVertical pod autoscaling(垂直podオートスケーリング)

スケールアウトはサーバーの台数を増やすこと、スケールアップはサーバーのスペックを上げることだが、
podをスケールアップはまだサポートされていない。が、今後サポートされるであろう。
podのスケールアップというのは、podのresource requests or limitsを変更するということ。

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を設定できる。
  • kubectl drain <node>でnodeにunschedulableを設定し、node上のpodを追い出す。
  • kubectl uncordon <node>を実行すればnodeのunschedulableを解除できる。

cluster scale down時にサービスの中断を抑える

nodeが突然死んだ場合はどうしようもないが、手動もしくはCluster Autoscalerでnodeの削除が行わえる場合は、サービスを中断させないことができる。
DisruptionBudgetリソースを作成すればよい。
参考: https://qiita.com/tkusumi/items/946b0f31931d21a78058
「PodDisruptionBudget とは Node を計画的に停止したい場合に、Pod の状況を見ながら退去 (evict) させる機能です」

まとめ

  • podの水平スケーリング(scale out)はHorizontalPodAutoscalerリソースを作成し、それをDeployment, ReplicaSetに指定し、対象CPU使用量を指定することで簡単にできる。
  • podのCPU使用量の他に、アプリケーションが提供するcustom metricsやclusterにdeployされている他のリソースのmetricsをもとにauto scalingすることができる。
  • 垂直スケーリング(scale up)はまだ提供されていない
  • (cloud providerから提供されていれば)cluster nodeもautoscalingできる。

参考