APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

AKSでVertical Pod Autoscaler(プレビュー)を試してみた

はじめに

こんにちは。ACS事業部)土居です。
本記事はエーピーコミュニケーションズ Advent Calender 2022 17日目の記事になります。

2022年10月2日のAKS ReleaseにてVertical Pod Autoscaler(以降VPAと呼ぶ)がプレビュー扱いになりました。 丁度Microsoft IgniteやKubeCon + CloudNativeCon North America 2022 の開催が近かった事もあり、この時期周辺ではAKSに多くのアップデートがありましたが、個人的に待ち望んでいた機能の一つです。

Vertical Pod Autoscalerとは?

Vertical Pod AutoscalerはPodの垂直方向の自動スケーリングを行う機能です。
これだけだとちょっと分かりづらいので、AKSでの主なスケーリングに関する機能とその位置づけを見ながら比較していきます。

スケーリングに関する機能 説明
Horizontal Pod Autoscaler(HPA) Podの水平方向の自動スケーリングを行います。HPAはDeploymentreplicasを増減することでスケーリングを実現します。
KEDA(プレビュー) KEDAもPodの水平方向の自動スケーリング機能です。内部的にKEDAはHPAと連携して動作します。KEDAの特徴として、イベント駆動型のスケーリングを実現できる点です。HPAではCPU,Memoryなど主にk8sのmetricsを監視したスケーリングを実現します。KEDAは、Azure Service BusAzure Storage キュー のキューの長さ, Azure Event Hubsのイベント数など外部サービスを監視したスケーリングが実現できます。KEDAに関しては、弊社のブログでも紹介しているので気になる方は御覧ください。
Vertical Pod Autoscaler(VPA)(プレビュー) Podの垂直方向の自動スケーリングを行います。VPAはPodrequestを増減することでPodが利用するリソースを調整することが可能です。HPA、KEDAと異なりPodの数を増やしてスケーリングするわけではありません。
Cluster Autoscaler Cluster AutoscalerはAKS Workerノードの水平方向の自動スケーリングを行います。AKSのWorkerノードの実態はVirtual Machine Scale Setsなので、VMSSのスケーリングと内部的にはリンクしています。

HPAの動作イメージ

VPAの動作イメージ

Cluster Autoscalerの動作イメージ

AKSでは、HPA、Cluster Autoscalerを使ったスケーリングの設定を行うことが今まで多かったのですが、今後の選択の幅が広がったと感じています。
一方で、VPAはHPA(KEDA)と組み合わせる事は複雑かつ動作安定性に欠けるため推奨されていなかったりと使い方が難しいとも思います。

Vertical Pod Autoscaler should not be used with the Horizontal Pod Autoscaler (HPA) on CPU or memory at this moment. However, you can use VPA with HPA on custom and external metrics.

github.com

以降、AKSでVPAを動かしてみながら利用できそうなシーンを考えてみます。

AKSにVPAを導入する

公式のドキュメントに細かな手順がありますので、こちらを参考に行っていきます。

learn.microsoft.com

まずはAKSクラスターを作成していきます。本記事執筆時点(2022.12.17)ではAKSの既定のKubernetes Versionは1.23系になっています。VPAは1.24以上で導入可能なので注意しましょう。

az aks create --resource-group doi-test --name doi-test --node-count 1 --node-vm-size Standard_B2ms --kubernetes-version 1.24

VPAの機能はプレビュー扱いのため、aks-vpapreview プレビュー機能をインストールしましょう。

az feature register --namespace Microsoft.ContainerService --name AKS-VPAPreview

作成したAKSクラスターに対してVPAの機能を有効化します。

az aks update --resource-group doi-test --name doi-test --enable-vpa

VPA有効化の前後で、kubectl get podを使った比較を行いました。vpa-admission-controller , vpa-recommender , vpa-updater の3つのコンポーネントがそれぞれ追加されている事が確認できます。

# VPA有効化前のkubectl get podの出力
k_doi@Azure:~$ kubectl get pod --all-namespaces
NAMESPACE     NAME                                  READY   STATUS        RESTARTS   AGE
kube-system   azure-ip-masq-agent-tvsqg             1/1     Running       0          2m14s
kube-system   cloud-node-manager-zhjhc              1/1     Running       0          2m14s
kube-system   coredns-59b6bf8b4f-6qclw              1/1     Running       0          79s
kube-system   coredns-59b6bf8b4f-qfd66              1/1     Running       0          2m33s
kube-system   coredns-autoscaler-5655d66f64-gvp9c   1/1     Running       0          2m33s
kube-system   csi-azuredisk-node-xpf9l              3/3     Running       0          2m14s
kube-system   csi-azurefile-node-hg9ps              3/3     Running       0          2m14s
kube-system   konnectivity-agent-595665fdfb-nbpcc   1/1     Running       0          2m33s
kube-system   konnectivity-agent-595665fdfb-rx7t2   1/1     Running       0          2m33s
kube-system   kube-proxy-fdk4l                      1/1     Running       0          2m14s
kube-system   metrics-server-58df99c858-gwfh4       2/2     Terminating   0          2m32s
kube-system   metrics-server-7dd74d8758-h866j       2/2     Running       0          73s
kube-system   metrics-server-7dd74d8758-nztvj       2/2     Running       0          73s
# VPA有効化後のkubectl get podの出力
k_doi@Azure:~$ kubectl get pod --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   azure-ip-masq-agent-tvsqg                  1/1     Running   0          5m23s
kube-system   cloud-node-manager-zhjhc                   1/1     Running   0          5m23s
kube-system   coredns-59b6bf8b4f-6qclw                   1/1     Running   0          4m28s
kube-system   coredns-59b6bf8b4f-qfd66                   1/1     Running   0          5m42s
kube-system   coredns-autoscaler-5655d66f64-gvp9c        1/1     Running   0          5m42s
kube-system   csi-azuredisk-node-xpf9l                   3/3     Running   0          5m23s
kube-system   csi-azurefile-node-hg9ps                   3/3     Running   0          5m23s
kube-system   konnectivity-agent-595665fdfb-nbpcc        1/1     Running   0          5m42s
kube-system   konnectivity-agent-595665fdfb-rx7t2        1/1     Running   0          5m42s
kube-system   kube-proxy-fdk4l                           1/1     Running   0          5m23s
kube-system   metrics-server-7dd74d8758-h866j            2/2     Running   0          4m22s
kube-system   metrics-server-7dd74d8758-nztvj            2/2     Running   0          4m22s
kube-system   vpa-admission-controller-b4f5d975d-2x2pn   1/1     Running   0          84s
kube-system   vpa-recommender-5fd94767fb-l6z6f           1/1     Running   0          84s
kube-system   vpa-updater-56f9bfc96f-fr5vx               1/1     Running   0          84s

VPAは以下の3つのコンポーネントから構成されています。

コンポーネント 説明
Recommender metrics serverからPodのメトリクスを取得し、Resource Requestの推奨値を計算する
Updater VPAの定義に従い、推奨値から外れたResource Requestを持ったPodを削除する
Admission Controller Resource Requestの値を書き換え、Podを再作成する

kubernetes/autoscaler GitHub リポジトリから Vertical Pod Autoscaler の例のマニフェストを利用します。 まずは、Deployment部分だけApplyしてみます。

kubectl apply -f deployment_vpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hamster
spec:
  selector:
    matchLabels:
      app: hamster
  replicas: 2
  template:
    metadata:
      labels:
        app: hamster
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody
      containers:
        - name: hamster
          image: k8s.gcr.io/ubuntu-slim:0.1
          resources:
            requests:
              cpu: 100m
              memory: 50Mi
          command: ["/bin/sh"]
          args:
            - "-c"
            - "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"

このDeploymentresource.requestsでCPU 100 millicores , Memory 50 Mi のリソースを予約しています。kubectl describe nodeからも確認できます。
一方で、実際の使用リソースは設定されているresource.requestsとはかけ離れており、CPU 450 millicores前後、Memory 1 Mi となっています。

k_doi@Azure:~$ kubectl describe node
Name:               aks-nodepool1-26322312-vmss000002
Roles:              agent
︙
︙
Non-terminated Pods:          (16 in total)
  Namespace                   Name                                   CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                   ------------  ----------  ---------------  -------------  ---
  default                     hamster-78f9dcdd4c-44d8d               100m (5%)     0 (0%)      50Mi (0%)        0 (0%)         16m
  default                     hamster-78f9dcdd4c-9th2v               100m (5%)     0 (0%)      50Mi (0%)        0 (0%)         16m
︙
︙
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests      Limits
  --------           --------      ------
  cpu                1170m (61%)   10990m (578%)
  memory             1480Mi (27%)  8818Mi (164%)
k_doi@Azure:~$ kubectl top pod
NAME                       CPU(cores)   MEMORY(bytes)   
hamster-78f9dcdd4c-44d8d   455m         1Mi             
hamster-78f9dcdd4c-9th2v   457m         1Mi        

次に、kubernetes/autoscaler GitHub リポジトリから Vertical Pod Autoscaler の例のマニフェストからVPA部分をApplyしてみます。spec.resourcePolicy.containerPolicies[].resources.minAllowedspec.resourcePolicy.containerPolicies[].resources.maxAllowedでVPAで割り当て可能なリソースの下限上限を設定が可能です。
また、spec.updatePolicy.updateModeを指定することで、VPAによるPod再作成等の動作を変更することができます。今回は指定していないため、Autoが適用されます。詳細は下記を参照下さい。

updateMode 説明
Auto Pod の作成時にリソース要求を割り当て、優先更新メカニズムを使用して既存の Pod でそれらを更新します。
Recreate Autoとほぼ同様
Initial ポッドの作成時にのみリソース リクエストを割り当てる
Off ポッドのリソース要件を自動的に変更しません。推奨事項のみ計算されます

github.com

k_doi@Azure:~$ kubectl apply -f vpa.yaml 
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
  name: hamster-vpa
spec:
  # recommenders field can be unset when using the default recommender.
  # When using an alternative recommender, the alternative recommender's name
  # can be specified as the following in a list.
  # recommenders: 
  #   - name: 'alternative'
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: hamster
  resourcePolicy:
    containerPolicies:
      - containerName: '*'
        minAllowed:
          cpu: 100m
          memory: 50Mi
        maxAllowed:
          cpu: 1
          memory: 500Mi
        controlledResources: ["cpu", "memory"]

しばらくすると、Podが再作成されます。再作成されたPodのresource.requestsを確認すると、VPAにより適切な値で修正されていることがわかります。

k_doi@Azure:~$ kubectl describe pod hamster-78f9dcdd4c-grtll
Name:             hamster-78f9dcdd4c-grtll
Namespace:        default
︙
    State:          Running
      Started:      Sat, 17 Dec 2022 07:21:17 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        548m
      memory:     262144k
    Environment:  <none>

VPAのマニフェストがどのような推奨値を計算しているか、kubectl describe vpaStatus.Recommendation.Container Recommendationsの確認ができます。
TargetがVPAが計算したrequestsの推奨値で実際にrequestsとして置き換えられる値でもあります。(若干値が異なるのは筆者のコマンド実行タイミングの問題なので気にしないで下さい。)
Uncapped Targetspec.resourcePolicy.containerPolicies[].resources.maxAllowedで設定したリソース上限を無視した状態でVPAが計算したrequestsの推奨値になります。

k_doi@Azure:~$ kubectl describe vpa hamster-vpa
︙
︙
Spec:
  Resource Policy:
    Container Policies:
      Container Name:  *
      Controlled Resources:
        cpu
        memory
      Max Allowed:
        Cpu:     1
        Memory:  500Mi
      Min Allowed:
        Cpu:     100m
        Memory:  1Mi
  Target Ref:
    API Version:  apps/v1
    Kind:         Deployment
    Name:         hamster
  Update Policy:
    Update Mode:  Auto
Status:
  Conditions:
    Last Transition Time:  2022-12-17T07:20:16Z
    Status:                True
    Type:                  RecommendationProvided
  Recommendation:
    Container Recommendations:
      Container Name:  hamster
      Lower Bound:
        Cpu:     503m
        Memory:  262144k
      Target:
        Cpu:     587m
        Memory:  262144k
      Uncapped Target:
        Cpu:     587m
        Memory:  262144k
      Upper Bound:
        Cpu:     1
        Memory:  500Mi
Events:          <none>

以下の理由から、個人的にはVPAはupdateModeOffにして、計算された推奨値を確認するために利用するのが現状は適していると考えています。

  • Podのrequestsが変更されることにより、他のPodのスケールにも影響を及ぼす可能性がある。

  • Deploymentのマニフェストのrequestの定義と実態が異なる可能性がある。

  • Podのrequestsの適正な値を見つけることは難しい(モニタリングツールとにらめっこすることが多々ある)

おわりに

いかがだったでしょうか?AKSでのVPA利用はまだプレビュー段階ですが、正式なリリースが出るのが楽しみですね。

私達ACS事業部はAzure・AKSを活用した内製化のご支援をしております。ご相談等ありましたらぜひご連絡ください。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
切磋琢磨しながらスキルを向上できる、エンジニアには良い環境だと思います。ご興味を持っていただけたら嬉しく思います。

www.ap-com.co.jp

本記事の投稿者: 土居 幸平