この記事は HPA v1(v2beta1) ベースとなっており、現在(2021/12)では非推奨の方法となっております。最新の内容は https://qiita.com/shmurata/items/e6bd8c56f3e4f9a8e384 にまとめていますのでこちらを参照ください
この記事ではKuberentesのオートスケール機能の一つであるHorizontal Pod Autoscalerについてまとめていきます。
Horizontal Pod Autoscaler
Horizontal Pod AutoscalerはReplicationControllerまたはDeployment, ReplicaSetのPodの数を自動的にスケールします。スケールの判定に利用するメトリクスはCPUやカスタムメトリクスを利用することができます。
Horizontal Pod AutoscalerはKubernetes APIオブジェクトとコントローラとして実装されています。このコントローラは定期的にユーザによって設定されたしきい値とメトリクスの値を比較しReplica数を調整します。
Horizontal Pod Autoscalerの動き
Horizontal Pod Autoscalerのコントローラ(HorizontalPodAutoscalerController)はControllerManagerにあるコントローラの一つとして実装されていて、デフォルトではコントロールループ(メトリクスの値を収集してReplica数を調整する処理のループ)は30秒間隔で周期しています。この間隔はControllerManagerの--horizontal-pod-autoscaler-sync-period
フラグで変更することができます。
このコントローラが扱うメトリクスはPod一つの単位で生成されるメトリクス(例:PodのCPU使用率)と全体で一つのメトリクス(例:アプリケーション全体のリクエスト数)があります。Pod一つの単位で生成されるメトリクス(per-pod metrics)には注意が必要で、この場合は一部のPodのメトリクスが取得できない場合は考慮しなければいけません。
HorizontalPodAutoscalerControllerはRequestが設定されていない場合はなんのアクションもしません。詳細は
autoscalerアルゴリズムに記載されています。
HorizontalPodAutoscalerControllerがメトリクスを収集する方法は2種類あります。一つは直接Heapsterにアクセスして取得する方法で、もう一つはREST clientでアクセスする方法です。直接HeapsterにアクセスするときにはAPIサーバのServiceProxySubResourceを通してアクセスします。このときHeapsterはkube-system
名前空間で動作するようにデプロイされている必要があります。REST clientでのアクセスについては後述するカスタムメトリクスについてのところで記載します。
API version
HorizontalPodAutoscalerはautoscaling
API Groupのオブジェクトです。2018/5/9時点ではCPU使用率のautoscalingのみがstableとなっていてautoscaling/v1
で提供されています。メモリ使用率によるスケールやカスタムメトリクスでのスケールはautoscaling/v2beta1
で提供されています。autoscaling/v2
のリリース時期については現在はまだ未確定のようです。
利用方法
Heapsterが既にデプロイされている環境なら以下のHorizontalPodAutoscalerオブジェクトを作成するだけで利用することができます。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: WebFrontend
namespace: default
spec:
# オートスケールさせるターゲットを設定
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: WebFrontend
# downscaleする最小値
minReplicas: 2
# upscaleする最大値
maxReplicas: 5
# すべてのPodの平均CPU使用率の目標値(%の値を設定する)
targetCPUUtilizationPercentage: 70
ここで重要なのはHorizontalPodAutoscalerControllerはメトリクスを収集してすべてのPodの平均値が指定した値(targetCPUUtilizationPercentage)に近づくようにReplicasを調整するということです。つまり上記の設定であれば平均CPU使用率が70%を超えていたらupscaleし、70%に届かない場合はdownscaleします。Pod数の計算式は以下になります。
TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / targetCPUUtilizationPercentage)
利用する上での注意事項
ReplicationControllerの場合はローリングアップデートするとHorizontalPodAutoScalerの対象から外れる
現在は殆ど使っている人はいないと思いますがHorizontalPodAutoScalerをReplicationControllerで利用している場合には注意が必要です。kubectl rolling-update
コマンドなどでReplicationControllerのローリングアップデートを行うと新たなオブジェクトが作成されるためHolizontalPodAutoScalerの対象に新しいオブジェクトはバインドされません。HorizontalPodAutoscalerを利用する場合はDeploymentを利用しましょう。
スラッシングが発生する場合はControllerManagerのパラメータを調整する
メトリクスは動的に評価される値のため頻繁にupscale/downscaleされることがあります。これをスラッシングというらしいです。これを緩和するためにControllerManagerには--horizontal-pod-autoscaler-downscale-delay
と--horizontal-pod-autoscaler-upscale-delay
というパラメータがあります。これらのパラメータはdownscaleまたはupscaleが行われた場合に同じ処理を再度行う際に設定した時間待ってから処理するというものです。downscaleはデフォルト5分、upscaleはデフォルト3分となっています。このパラメータは長くするとその分upscale/downscaleが遅れることになるので調整する場合は注意が必要です。
v2からサポートされる機能
マルチメトリクス
複数のメトリクスによるオートスケールが可能になりました。複数設定した場合な各メトリクスに基づいて評価し最大のReplicasが採用されます。
複数設定するには以下のように設定します。
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
spec:
scaleTargetRef:
kind: Deployment
name: WebFrontend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 80
- type: Object
object:
target:
kind: Service
name: Frontend
metricName: hits-per-second
targetValue: 1k
各値の詳細などはこちらに定義があるので参照してください。
カスタムメトリクス
カスタムメトリクスによるオートスケーリングが可能になりました。
これを利用するためには次の設定をしなければなりません。
- API aggregationの設定
- APIサーバを経由して任意のサービスにアクセスするための機能です
- 設定の方法などはこちらを参照してください
- ControllerManagerを設定する
-
--horizontal-pod-autoscaler-use-rest-clients
をtrueにする
-
minikubeであれば上記は設定済みですので、特に設定などは不要です。カスタムメトリクスサーバは https://github.com/kubernetes-incubator/custom-metrics-apiserver にサンプルがあり、これをベースに作成すると良さそうですが、今回は予め用意されたサンプルを利用して設定してみます。
内容が若干古いですが https://docs.bitnami.com/kubernetes/how-to/configure-autoscaling-custom-metrics/ にカスタムメトリクスの設定方法が記載されていたのでこの方法を参考にサンプルアプリケーションのカスタムメトリクスによるオートスケーリングを試してみます。
# サンプルのマニフェストが含まれるリポジトリを取得
$ git clone git@github.com:luxas/kubeadm-workshop.git
$ cd kubeadm-workshop
# Prometheusのデプロイ
# この例ではPrometheusのメトリクスを利用してオートスケーリングするためPrometheusを用意します
$ kubectl apply -f demos/monitoring/prometheus-operator.yaml
$ kubectl apply -f demos/monitoring/sample-prometheus-instance.yaml.yaml
# カスタムメトリクスサーバのデプロイ
$ kubectl apply -f demos/monitoring/custom-metrics.yaml
# 確認
$ kubectl api-versions
# custom.metrics.k8s.io/v1beta1 が登録されている
$ kubectl get --raw apis/custom.metrics.k8s.io/v1beta1
{"kind":"APIResourceList","apiVersion":"v1","groupVersion":"custom.metrics.k8s.io/v1beta1","resources":[{"name":"namespaces/scrape_duration_seconds","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]},{"name":"services/scrape_duration_seconds","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"jobs.batch/scrape_samples_post_metric_relabeling","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"namespaces/up","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]},{"name":"jobs.batch/http_requests","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"namespaces/http_requests","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]},{"name":"jobs.batch/scrape_duration_seconds","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"services/scrape_samples_post_metric_relabeling","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"services/scrape_samples_scraped","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"namespaces/scrape_samples_scraped","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]},{"name":"pods/scrape_samples_scraped","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"pods/http_requests","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"services/http_requests","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"pods/scrape_duration_seconds","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"namespaces/scrape_samples_post_metric_relabeling","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]},{"name":"pods/scrape_samples_post_metric_relabeling","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"jobs.batch/scrape_samples_scraped","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"jobs.batch/up","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"pods/up","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"services/up","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]}]}
# サンプルアプリケーションのデプロイ
$ kubectl apply -f demos/monitoring/sample-metrics-app.yaml
# hpa を確認
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
sample-metrics-app-hpa Deployment/sample-metrics-app 866m/100 2 10 2 2h
HPAの中身は以下のように設定されています。
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
name: sample-metrics-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sample-metrics-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Object
object:
target:
kind: Service
name: sample-metrics-app
metricName: http_requests
targetValue: 100
これはsample-metrics-appサービスのQPSが1Podあたり100QPSになるようにオートスケールが実施されるという設定になります。
実際に負荷をかけてみると以下のようにオートスケールが実施されました。
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
sample-metrics-app-hpa Deployment/sample-metrics-app 603/100 2 10 6 2h
参考
- https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
- https://github.com/kubernetes/community/blob/master/contributors/design-proposals/autoscaling/horizontal-pod-autoscaler.md#autoscaling-algorithm
- https://github.com/kubernetes-incubator/custom-metrics-apiserver
- https://docs.bitnami.com/kubernetes/how-to/configure-autoscaling-custom-metrics/