KubernetesのPodのオートスケールについて確認してみる
概要
KubernetesのオートスケールにはPodの数をスケールするHrizontal Pod AutoscalerとNodeの数をスケールするClusterAutoscalerの2種類が存在します。今回はHPAを中心にどのようにPodがスケールしているのかについて確かめていきます。
参考にしたドキュメントはこちら
- Horizontal Pod Autoscaler - Kubernetes
- autoscaler/cluster-autoscaler at master · kubernetes/autoscaler · GitHub
どのように設計すべきか
PodのオートスケールとNodeのオートスケールに関しての設計において、2つのオートスケールをどのように使い分けるか、ということが考えなければいけないことです。どちらのオートスケールをメインで使っていくかという点ですが、明らかにPodの起動時間 < Nodeの起動時間なので、Podのオートスケールで十分に捌ける用意をしておき、Nodeでのオートスケールは必要最小限に抑えるべきだと考えます。ピーク時のスパイクはPodのオートスケールで対応していきます。またNodeのスケールアウトはNodeが起動するまでの時間はできるだけ短い方が好ましく、スケールインまでの時間は長くても問題がありません。
以上の事柄から以下の項目に留意して設定していきます
- メトリクスを取得する時間間隔
- Podのmin, max、Nodeのmin, maxの設定
- Podがオートスケールする条件
- Nodeがオートスケールする条件
- スケールアウトするまでの時間
- スケールアウトするジョブ
Horizontal Pod Autoscaler
Horizontal Pod Autoscalerについてですが、仕組みについては以下のようになっています。
スケールアウト時
記した時間はデフォルトの値です
- 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%以上もしくは未満になる時にスケールダウンする
という、流れになります。スケールするまでにデフォルトの設定では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-clients
をfalse
に変更して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のスケールを制御する方法もあるので、機会があればそちらの方も確認したいです。