varu3/techBlog

IT infrastructure technology memo.

KubernetesのPodのオートスケールについて確認してみる

概要

KubernetesのオートスケールにはPodの数をスケールするHrizontal Pod AutoscalerとNodeの数をスケールするClusterAutoscalerの2種類が存在します。今回はHPAを中心にどのようにPodがスケールしているのかについて確かめていきます。

参考にしたドキュメントはこちら

どのように設計すべきか

 PodのオートスケールとNodeのオートスケールに関しての設計において、2つのオートスケールをどのように使い分けるか、ということが考えなければいけないことです。どちらのオートスケールをメインで使っていくかという点ですが、明らかにPodの起動時間 < Nodeの起動時間なので、Podのオートスケールで十分に捌ける用意をしておき、Nodeでのオートスケールは必要最小限に抑えるべきだと考えます。ピーク時のスパイクはPodのオートスケールで対応していきます。またNodeのスケールアウトはNodeが起動するまでの時間はできるだけ短い方が好ましく、スケールインまでの時間は長くても問題がありません。

以上の事柄から以下の項目に留意して設定していきます

  • メトリクスを取得する時間間隔
  • Podのmin, max、Nodeのmin, maxの設定
  • Podがオートスケールする条件
  • Nodeがオートスケールする条件
  • スケールアウトするまでの時間
  • スケールアウトするジョブ

Horizontal Pod Autoscaler

Horizontal Pod Autoscalerについてですが、仕組みについては以下のようになっています。

f:id:varu3:20180531113552p:plain

スケールアウト時

記した時間はデフォルトの値です

  • cAdviorがPodのメトリクスを収集する(10s毎)(kubeletの--housekeeping-interval)
  • kubeletがPodのCPU使用率を取得する (10s毎) (kubeletの--cpu-manager-reconcile-period)
  • HeapsterがそれぞれのNodeのkubeletからmetricsを収集と集計し、データをmaster metrics api経由でHPA controllerに公開する (60s毎) (heapsterの--metric_resolution)
  • HorizonalPodAutoscalerが収集したメトリクスの値と定義されたCPU使用率を比較する (30s毎) (kube-controller-managerの--horizontal-pod-autoscaler-sync-period)
  • HorizonalPodAutoscalerがReplicationControllerとDeploymentのレプリカ数を調整する
  • DeploymentsがReplicationControllerに働いて規定のPodの数にまで増やす
    • 規定のPod数の算出式: TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target)
  • 再スケーリングするまでに3分間待機する(kube-controller-managerの--horizontal-pod-autoscaler-upscale-delay)

スケールイン時

  • 最後のスケーリングから5分以上経過していないとスケールインしない
  • kubeletがPodのCPU使用量を取得する (10s毎)
  • HeapsterがそれぞれのNodeのkubeletから値を収集する (60s毎)
  • 現在のPodの使用量の平均 / Target が許容値の10%以上もしくは未満になる時にスケールダウンする
    • スケールダウンする条件式: avg(CurrentPodsConsumption) / Target drops below 0.9 or increases above 1.1

という、流れになります。スケールするまでにデフォルトの設定ではkubelet -> heapster -> hpaまでの時間100秒 + Podの起動時間がかかります。早くPodが起動できるようにそれぞれの数値をデフォルトから変更していく必要があります。ただし、Pod起動直後は一時的にCPU使用率が安定せずに増加することがあり、正確なメトリクスが取得されるまでに少々時間がかかることを考慮に入れなければなりません。

HPAの挙動の確認

HPAの有効化

以下の構成を組んでHPAの挙動を確認します。 Node1つとMaster1つの簡易な構成で組んでみます。今回はKOPSを使って構築しました。

$ kubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=100m --expose --port=80
$ kubectl get pods
NAME                          READY     STATUS    RESTARTS   AGE
php-apache-7ccc68c5cd-27c4g   1/1       Running   0          51s

以下のコマンドでHPAを有効にします。

$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
deployment "php-apache" autoscaled

Podのメトリクス収集について

本題と少々それるのですが、以下のようになって、HPAのメトリクスが取得できないことがあります。

$ kubectl get hpa
NAME         REFERENCE               TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   <unknown> / 50%   1         10        1          56s

正常にメトリクスが収集されていないようです。

$ kubectl describe hpa php-apache
...
 ScalingActive  False   FailedGetResourceMetric  the HPA was unable to compute the replica count: unable to get metrics for resource cpu: unable to fetch metrics from API: the server could not find the requested resource (get pods.metrics.k8s.io)

調べてみたところ、kubernetes1.8からheapsterではなく後継のmetrics-serverがリソースの使用量のデータなどを収集するようになったそうです。これを従来のHeapsterで制御するように変更するのには、kube-controller-managerの--horizontal-pod-autoscaler-use-rest-clientsfalseに変更してheapsterをdeployすれば、取得できるようになります。 Kopsでの変更は以下のようにすると良いでしょう。

$ kops edit cluster
...
  kubeControllerManager:
    horizontalPodAutoscalerUseRestClients: false
...

ただ、これからheapsterの後継のmetrics-serverに切り替わるらしいので、ここをいじることはせず、metrics-serverをつかうようにしたほうがいいかもしれません。その場合のインストール方法は以下の通りです。

horizontalPodAutoscalerUseRestClients: trueの状態で
$ git clone https://github.com/kubernetes-incubator/metrics-server.git
$ cd metrics-server
$ kubectl create -f deploy/1.8+/

これでmetrics-serverがデプロイされ、正常にメトリクスが収集されるようになります。従来のHeapsterのオプションもそのまま使えるようですので、ここではこのまま話を進めます。

Podに負荷を与える

改めて設定を確認してみます。

$ kubectl get hpa
NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0% / 50%   1         10        1          5h
$ kubectl describe hpa
Name:                                                  php-apache
Namespace:                                             default
Labels:                                                <none>
Annotations:                                           <none>
CreationTimestamp:                                     Wed, 30 May 2018 11:24:18 +0900
Reference:                                             Deployment/php-apache
Metrics:                                               ( current / target )
  resource cpu on pods  (as a percentage of request):  459% (918m) / 50%
Min replicas:                                          1
Max replicas:                                          10

こちらの設定では、CPU使用率が50%で1~10つまでのpodが増減します。それでは、実際に負荷を与えてみます。

$ kubectl run -i --tty load-generator --image=busybox /bin/sh
> while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!…

しばらくすると、TARGETのCPU使用率が上がってREPLICASも増えます。

$ kubectl get hpa
NAME         REFERENCE               TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   133% / 50%   1         10        4          5h
$ kubectl get pods
NAME                              READY     STATUS    RESTARTS   AGE
load-generator-5c4d59d5dd-92xfh   1/1       Running   0          4m
php-apache-7ccc68c5cd-8qd7r       1/1       Running   0          19m
php-apache-7ccc68c5cd-96vms       1/1       Running   0          2m
php-apache-7ccc68c5cd-bp2lw       1/1       Running   0          2m
php-apache-7ccc68c5cd-xnrc4       1/1       Running   0          2m

while loopを止めるとpodの数も元に戻ります。

HPAまでの時間を調整する

ここまでで、HPAによるPodのスケールについて確認できましたが、Podのスケールアウトまでの時間をもう少し短くしたいです。今回は、設定する項目を以下の2つに絞ります。

  • kube-controller-managerの--horizontal-pod-autoscaler-sync-period
  • kube-controller-managerの--horizontal-pod-autoscaler-upscale-delay

Podの実際のメトリクスと定義したメトリクスを比較するhorizontal-pod-autoscaler-sync-periodと、スケールアップしてからの待機時間であるhorizontal-pod-autoscaler-upscale-delayです。

horizontal-pod-autoscaler-sync-periodを短くすると、PodのCPU使用率が上がりきる前にスケールが始まり、中途半端なPod数で3分間待機するということになるので、スケールの待機時間の方も短くします。 kopsでは以下のように設定しました。

$ kops edit cluster 
...
  kubeControllerManager:
    horizontalPodAutoscalerSyncPeriod: 5s
    horizontalPodAutoscalerUpscaleDelay: 30s
    horizontalPodAutoscalerUseRestClients: true
...

これでHPAがスケールアウトするまでの時間を短くすることができます。

終わりに

今回はPodのHPAについてを紹介しました。この他にもClusterAutoscalerというNodeのスケールを制御する方法もあるので、機会があればそちらの方も確認したいです。