Kubernetesにおけるオートスケーリングの概要
はじめに
Kubernetesにはリソースの利用状況に応じてオートスケールする仕組みがあります。この仕組みを上手く利用することで、従来は手動で行なっていた「パフォーマンス管理」や「キャパシティー・プランニング」の一部を自動化することができます。本連載では、Kubernetesのオートスケールに関して説明していきます。
Kubernetesにおけるオートスケール
Kubernetesのオートスケールは、スケールする対象が異なる以下の2種類があります。
- Podのオートスケール
Podのリソース使用量を評価して、Podに対するリソースの割り当てをコントロールします。 - クラスタのオートスケール
クラスタのリソース使用量を評価し、ノードの増減等を行うことでクラスタで利用できるリソース量をコントロールします。
Kubernetesでオートスケールを利用する場合は、まずアプリケーションの性能要件に合わせてPodのオートスケールを設定します。その際にPodへのリソースの割り当ての増加により、クラスタ内のリソースが枯渇するのを防ぐためにクラスタのオートスケールを設定するというのがよくあるユースケースです。
オートスケールを実施する目的
リソースを「増やす」と「減らす」では、それぞれの仕組みや挙動が異なる点に注意が必要ですが、それぞれを設定する目的が異なる点も意識する必要があります。実際のユースケースでは以下の目的を持って設定することが多いと思います。
- リソースを増やす
リソース不足によって、アプリケーションが期待される性能発揮できなくなるのを防ぐために設定します。 - リソースを減らす
余剰リソースを削減することで、コストの最適化を行います。
これから紹介するオートスケールに関するどの機能を利用するにしても、まずは自分たちがリソースの増減によってどういう状態を実現していきたいかをはっきりさせる必要があります。
Podのオートスケール
Podのオートスケール方法である、以下の3つの方法について概要を説明します。
- 水平スケール: HorizontalPodAutoscaler(HPA)
- 垂直スケール: VerticalPodAutoscaler(VPA)
- 多次元(水平垂直)スケール: MultidimensionalPodAutoscaler(MPA)
Podの水平スケール
KubernetesではPodを水平スケールさせるHorizontalPodAutoscaler(HPA)という仕組みが標準で用意されています。Podのリソースの使用状況に応じてPod数を自動で増減するように設定できます。以前はv1
と呼ばれる仕組みがありましたが、現在はKubernetes v1.23からGAとなったHPAのv2
という仕組みを利用するようにしてください。
HPAのv2を利用する場合は、以下のようなマニフェストを利用して設定します。
・HPAのリソースの例apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: hpa-sample spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpa-sample minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50
こちらの機能は、CPUの使用率が増えた場合にPod数を増やしたいなどのユースケースでよく使われます。
【参考】HPAに関するKubernetesの公式ドキュメントの説明
Podの垂直スケール
KubernetesではPodを垂直スケールさせるVerticalPodAutoscaler(VPA)が用意されていますが、こちらはHPAとは異なり標準では利用できる状態になっていません。コミュニティで開発されているVPAのコントローラーを自分でKubernetesクラスタにデプロイすることで利用できるようになります。利用するKubernetesサービスによっては有効化するだけでVPAを利用できるものもあります。VPAは現在1.0(GA)となっており、Kubernetes v1.25以上が動作環境になります。
VPAを利用する場合は、以下のようなマニフェストを利用して設定します。
・VPAのリソースの例apiVersion: "autoscaling.k8s.io/v1" kind: VerticalPodAutoscaler metadata: name: vpa-sample spec: targetRef: apiVersion: "apps/v1" kind: Deployment name: vpa-sample resourcePolicy: containerPolicies: - containerName: '*' minAllowed: cpu: 100m memory: 50Mi maxAllowed: cpu: 1 memory: 500Mi controlledResources: ["cpu", "memory"]
こちらの機能はアプリケーションのメモリ使用量が増えた場合に、より多くのメモリを割り当てたいなどのユースケースで使われます。ただ、Podのリソースの割り当てを変更する際に、Podを再作成するのか、既存のPodのリソース量を変更するのかなど、水平スケールと比べてより多くのことを検討して使用する必要があるので、注意が必要です。
【参考】コミュニティで開発されているVPAに関するGithubのリポジトリ
Podの多次元(水平垂直)スケール
KubernetesではPodを多次元(水平垂直)スケールするMultidimensionalPodAutoscaler(MPA)という仕組みがコミュニティで提案されています。こちらの機能は提案のみで、まだコミュニティで実装の開発はされていません。しかし、Google Kubernetes Engine(GKE)の場合は独自に実装されたものがあり、利用できます。
MPAを利用する場合は、以下のようなマニフェストを利用して設定します。
・MPAのリソースの例apiVersion: autoscaling.gke.io/v1beta1 kind: MultidimPodAutoscaler metadata: name: mpa-sample spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: mpa-sample goals: metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 constraints: global: minReplicas: 1 maxReplicas: 5 containerControlledResources: [ memory ] container: - name: '*' requests: minAllowed: memory: 1Gi maxAllowed: memory: 2Gi policy: updateMode: Auto
こちらの機能を使う場合はHPAとVPAを併用した場合の課題について理解する必要があります。HPAとVPAを同じPodに対して設定した場合にPodのリソースの状況によってはオートスケールによる増減が頻繁に繰り返されて不安定な状態になるリスクがあります。
そこで、水平・垂直のオートスケールで設定できるリソースの変動の条件に以下の制約を課すことで、Podに水平・垂直スケールを同時に設定してもPodの状態が安定するように配慮された機能になります。
- 水平スケール: CPU使用量の変動に応じてのみ設定できる
- 垂直スケール: メモリ使用量の変動に応じてのみ設定できる
こちらの機能はHPAとVPAを同時に設定した場合のリスクを抑制することに価値があるので、Podの垂直スケールを利用したけどPodの水平スケールも実施したい場合に、HPAとVPAのリソースの作成を禁止して必ずMPAのリソースを使うなどの運用ルールを整備して利用することで、より効果を発揮する機能になります。
しかし、水平スケールにCPU使用量以外の条件(例えばアプリケーション1つあたりのリクエスト数)を設定したい場合などはMPAではなくHPAの機能を拡張して利用する必要があるので、利用したい条件に応じで運用する際のルールをより細かく設定して使用する必要があります。
多次元スケールは水平・垂直スケールと比較して複雑な仕組みになるためより多くのことを検討する必要がありますが、使いこなせばより多くのことが実現できる魅力的な機能でもあります。
【参考】コミュニティ管理されているMPAの機能提案に関するドキュメント
【参考】MultidimPodAutoscalerに関するGoogle Cloudのドキュメント
クラスタのオートスケール
クラスタのオートスケール方法である、以下の3つについて概要を説明します。
- Cluster Autoscaler(CAS)
- Karpenter
- GKE Autopilot
Cluster Autoscaler
Cluster Autoscalerは、クラスタのリソースの利用状況に応じてノード数を増減させる仕組みです。こちらはコミュティで参考となる実装が公開されているので、そちらを元に自分たちの環境で動作するcloudproviderと呼ばれる機能を追加で実装すると利用できるようになります。利用するKubernetesサービスによっては既に実装されており、有効化するだけで使えるサービスもあります。
こちらの機能はPodを新規作成したときにクラスタ内のリソース不足でスケジュールできない場合に、Cluster Autoscalerが外部サービス(OpenStackやAWS、GCE、Azureなど)にノードの新規作成を依頼することで、クラスタ内で使用できるリソース量を増やすというのが簡単な機能の説明になります。Cluster Autoscalerはあくまでノードの新規作成や削除の指示を出すだけなので、ノードの作成削除の時間等については外部サービスに依存します。
また、クラスタ内のリソースの状況に応じてノードの削除も行いますが、以下のような条件に該当するPodがノードに存在する場合はノードが削除されないため、思ったようにリソースの削減によるコスト削減が進まないことがあります。
・Cluster Autoscalerがノードの削減をしない条件の例- PodDisruptionBudget(PDB)によって制限されているPod
- DeploymentやJob、StatefulSetなどのコントローラーによって管理されていないPod
- LocalStorageを利用するように設定されているPod
- スケジュールなどの様々な条件によって、他に移動できるノードが存在しないPod
上記については、対象のPodに"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"
のアノテーションを追加することで除外できるため、ノードの削除が期待通りいかない場合は、削除を期待するノードで動作しているPodの状態を確認して条件に対応するように変更を加えるか、Podに該当のアノテーションを付与していくことになります。
こちらの機能は仕組みが少し複雑なので使いこなすのが少し難しいですが、うまく使いこなすと手動で行っていたキャパシティプランニングの一部を自動化できるようになるため、魅力的な機能となっています。
【参考】コミュニティで開発されているCluster Autoscalerに関するGithubのリポジトリ
Karpenter
KarpenterもCluster Autoscalerと同様に、スケジュールできないPodが存在する場合にノードを追加する機能です。
Cluster Autoscalerに対応するノードプール内のノード数を増減させることでクラスタ内で利用できるリソースをコントロールするという考え方になります。その結果どういうことが起こるかというと、ノードを追加するときに既存のクラスタのノードと同一の量のCPUとメモリが搭載されているノードを追加するような形になります。例えば、メモリがもっと少ないノードを追加するだけで十分な場合に、過剰なリソースのノードが追加されて期待しているよりも多くのコストがかかるケースなどがあります。
Karpenterでは、クラスタにノードを追加する際により柔軟に追加するノードの候補を選択してくれるため、ノード追加時に余剰のリソースが発生しづらいという特徴があります。
Karpenterは元々AWSで開発されていましたが、コア機能部分についてはコミュニティに寄贈されました。開発の経緯もあり今まではAWSのみで利用可能でしたが、現在はAzureでも利用できるようになっています。
Karpenterはまだバージョンが1.0
になっていませんが、今後はKarpenterが利用できるKubernetesサービスを利用する際はCluster AutoscalerではなくはKarpenterを利用することが一般的になることも考えられる注目の機能です。
【参考】コミュニティで開発されているKarpenterに関するGithubのリポジトリ
【参考】Karpenterの公式ドキュメント
【参考】AWSのKarpenterに関するGithubのリポジトリ
【参考】AzureのKarpenterに関するGithubのリポジトリ
GKE Autopilot
こちらはKubernetesの標準機能ではなく、GKEでのみ利用できるノードのリソース管理する機能です。実装が公開されていないため表面的な挙動からの推察にはなりますが、Cluster Autoscalerに独自の機能を追加し、拡張した機能というイメージになります。
GKE Autopilotはクラスタの運用に幾つかの制限を課す代わりに、ノードのリソース管理をGKE側に任せることができる機能です。
・GKE Autopilotを利用する際に発生する制約の一部- Kubernetes Pod Security StandardsのPrivilegedが利用できない(強い権限を持つPodを利用できない)
- ノードにSSHでアクセスできない
機能がリリースされた当初は多くの制限がありましたが、現在はだいぶ条件が緩和されて色々なユースケースで使えるようになっています。リソースの使用量が大きく変動する場合などは、自分たちでCluster Autoscalerを細く設定したり、手動でノードの追加を実装しないと要件を満たせないケースなどはありますが、上手く利用するとノード管理が楽になる有用な機能になります。
【参考】Autopilotに関するGoogle Cloudのドキュメント
Kubernetes以外でコンテナを管理してくれるプロダクト
多くの場合ではKubernetesを運用することが目的ではなく、コンテナでアプリケーションを運用する目的を達成するための手段としてKubernetesを利用していると思います。そのため、Kubernetesのオートスケールの機能の利用を検討する場合は、各ベンダーから提供されている以下のようなコンテナを動かせる機能も候補に挙げて検討を行い、要件により適したものを選択していくと運用を楽にしていくことができると思います。
- Cloud Run: https://cloud.google.com/run?hl=ja
- Amazon Elastic Container Service: https://aws.amazon.com/jp/ecs/
- Azure Container Apps: https://azure.microsoft.com/ja-jp/products/container-apps/
本連載ではKubernetesにおけるオートスケーリングに焦点を当てていくため上記についてはあまり触れませんが、実際のプロダクト運用を考える際には検討してみると良いと思います。
おわりに
今回は連載の第1回ということで、オートスケーリングに関する全体の概要について触れていきました。オートスケーリングについては色々な場所でドキュメントが管理されているので、みなさんの知らない情報が1つか2つ程度はあったのではないでしょうか。次回以降は、今回紹介した各項目について、深掘りしていきたいと思います。
また、今回の記事に関する感想や「こんな内容について書いてほしい!」などの要望があれば、下記の「Xポスト」ボタンを押して、ぜひお知らせいただけると嬉しいです。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Oracle Cloud Hangout Cafe Season 4 #5「Kubernetesのオートスケーリング」(2021年8月4日開催)
- ドメインを考慮した柔軟なPodの配置を実現する「Balancer」
- KubernetesのDiscovery&LBリソース(その2)
- Podのリソース割り当ての推奨値を提案するKRR(Kubernetes Resource Recommender)
- KubernetesのDiscovery&LBリソース(その1)
- Kubernetesの基礎
- Kubernetesアプリケーションのモニタリングことはじめ
- 「K8sGPT」の未来と生成AIを用いたKubernetes運用の最前線
- Kubernetes上のコンテナをIngressでインターネットに公開するまで
- OpenShift:アプリケーションの構成と運用