NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

Kubernetesのスケーリングについて触ってみた 〜Horizontal Pod AutoscalerとCluster Autoscaler〜

クラウド事業推進部の石倉です。

今回はKubernetesのスケーリングで利用されるPodのスケーリングをするHorizontal Pod AutoscalerとノードのスケーリングをするCluster Autoscalerについて手を動かしながら確認してみたのでハンズオンのような形で紹介します。

Horizontal Pod Autoscalerについて

まずはHorizontal Pod Autoscaler(以降HPA)についてです。
HPAはPodのスケーリングです。Deployment(Podを管理するリソース)などのターゲットに対してPodのCPU使用率などの理想値を設定し、理想値と現在値から計算してPodをスケーリングさせます。

何台にスケーリングさせるかの計算ロジックなどについてはドキュメントに載っています。

kubernetes.io

それでは早速手を動かしていきたいと思います。今回はAWSのEKS環境で確認していきます。

準備

まずはEKS環境を用意します。
eksctlというツールがあるので今回はそれを利用します。(eksctlのインストール手順はこちらのドキュメントを参考にしてください)
CloudShellなどから実行していきます。

eksctl create cluster --name ishikura-demo --region ap-northeast-1 --node-type t3.medium --nodes 1

これだけで必要なEKSノードやVPCなどのネットワークまわりが一緒に作成されます。(裏ではCloudFormationが動いています)

どんなオプションがあるかはeksctl create cluster --helpで確認できます。
今回は東京リージョンに「ishikura-demo」という名前のEKSクラスターで、t3.mediumのノードを1つ作成します。
ちなみにデフォルトだとm5.largeのノードが2つ作成されます。

HPAを試してみる

以下のマニフェストファイルをkubectl apply -f {ファイル名}で適用します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

内容としては、
・php-apacheアプリケーションを立てる(重い処理をした後にOK!と返すもの)
・アプリケーションを立てるには最低限200ミリコアを必要とする
・理想値をCPU使用率50%とし、1~10の範囲でPodをスケーリングさせるHPA設定
という感じです。

apply後はkubectl get node,pod,hpaなどで状態を確認しましょう。(この時点ではまだ負荷がないのでHPAのCPU使用率表示箇所は0%になっているかと思います)

$ kubectl get node,pod,hpa
NAME                                                   STATUS   ROLES    AGE     VERSION
node/ip-192-168-62-4.ap-northeast-1.compute.internal   Ready    <none>   4m23s   v1.32.3-eks-473151a

NAME                              READY   STATUS    RESTARTS   AGE
pod/php-apache-6487c65df8-7x24s   1/1     Running   0          83s

NAME                                             REFERENCE               TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/php-apache   Deployment/php-apache   cpu: 0%/50%   1         10        1          83s

準備ができたら負荷をかけてみます。watchコマンドなどで継続的に確認しておくと流れが見やすいと思います。 (負荷コマンドは別ターミナルから実行してください)

## watchコマンドで継続的に見る
watch kubectl get node,pod,hpa

## 負荷をかける
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

するとHPAのCPU使用率表示箇所の数値が上がり、php-apacheアプリケーションのPodが増えるのが見えると思います。

NAME                                                   STATUS   ROLES    AGE     VERSION
node/ip-192-168-62-4.ap-northeast-1.compute.internal   Ready    <none>   9m19s   v1.32.3-eks-473151a

NAME                              READY   STATUS    RESTARTS   AGE
pod/load-generator                1/1     Running   0          3m54s
pod/php-apache-6487c65df8-7x24s   1/1     Running   0          6m19s
pod/php-apache-6487c65df8-jppgt   1/1     Running   0          3m3s 
pod/php-apache-6487c65df8-jv7lq   1/1     Running   0          3m18s
pod/php-apache-6487c65df8-kg7s6   0/1     Pending   0          2m33s
pod/php-apache-6487c65df8-pntx6   1/1     Running   0          3m18s
pod/php-apache-6487c65df8-s6nb8   1/1     Running   0          2m48s
pod/php-apache-6487c65df8-sz9jf   0/1     Pending   0          2m48s
pod/php-apache-6487c65df8-w27xj   1/1     Running   0          3m18s
pod/php-apache-6487c65df8-xnnrj   0/1     Pending   0          2m33s

NAME                                             REFERENCE               TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/php-apache   Deployment/php-apache   cpu: 63%/50%   1         10        9          6m19s

ここではCPU使用率が63%となり、アプリケーションのPodが9台に増えています。
ですが、CPU使用率はまだ理想値を上回っている状態です。また、PendingのままとなっているアプリケーションのPodがありますね。
kubectl describe pod {Pod名}でPendingのままになっているアプリケーションのPodの状態を見てみます。

$ kubectl describe pod {Pending状態のPod名}
...
...
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  4m1s  default-scheduler  0/1 nodes are available: 1 Insufficient cpu. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.

今回はマニフェストファイルでphp-apacheアプリケーションのcpuのrequests値を200にしているため、アプリケーションのPodを立てるにはノードの空き容量に200ミリコア残っている必要があります。
ですがもうノードに空き容量が残っていないため、HPAによってPodを増やしたくても立てることができなくなっているという状態です。
実際にEKSコンソールからノードの状態を見ると利用可能なCPUが残っていないことが見てとれます。

ここで登場するのがCluster Autoscalerです。
もう、1つのノードではこれ以上Podを立てられないのでノード自体を増やしましょう。

次に行く前に負荷コマンドは停止しておいてください。

Cluster Autoscalerについて

Cluster Autoscalerはノードのスケーリングです。
Pending状態のPodを検知してノードのスケーリングをしてくれます。
AWS環境の場合はAutoScalingグループを操作してスケーリングさせています。

HPAでPodを増やそうとしたものの、ノード自体のリソース上限に達してしまいPodを新しく立てられなくなった場合にノード自体を増やすことでPodを立てられるようになります。

準備

Cluster Autoscalerを使うにあたりドキュメントに記載されている以下の2つを対応します。
・ノードのIAMロールへのIAMポリシーの付与
・マニフェストファイルの用意

github.com

ノードのIAMロールはEKSコンソールから確認できるので、そのIAMロールにドキュメントに記載されている内容のIAMポリシーを付与しておきます。

マニフェストファイルについてはドキュメントで用意されているファイルの以下の2箇所を直して作成します。

  1. 149行目のバージョンをEKSのKubernetesのバージョンに合わせます。 ドキュメントの例はv1.26ですが、今回はv1.32ですので直します。 バージョン履歴はこちらに載っています。
  2. 165行目のクラスター名を直します。

変更箇所の149~165行目はこんな感じです。

148      containers:
149        - image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.32.1  ## 変更箇所
150          name: cluster-autoscaler
151          resources:
152            limits:
153              cpu: 100m
154              memory: 600Mi
155            requests:
156              cpu: 100m
157              memory: 600Mi
158          command:
159            - ./cluster-autoscaler
160            - --v=4
161            - --stderrthreshold=info
162            - --cloud-provider=aws
163            - --skip-nodes-with-local-storage=false
164            - --expander=least-waste
165            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ishikura-demo  ## 変更箇所

Cluster Autoscalerを試してみる

準備したCluster Autoscalerのマニフェストファイルをapplyします。

kubectl apply -f {Cluster Autoscalerのマニフェストファイル}

ノードをスケーリングさせるために最大数を3に変更しておきます。

それでは再び負荷をかけてみます。

## watchコマンドで継続的に見る
watch kubectl get node,pod,hpa

## 負荷をかける
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

先ほどと同じようにPending状態のphp-apacheアプリケーションのPodが発生しますがそれを検知してノードのスケーリングがされます。

NAME                                                     STATUS   ROLES    AGE     VERSION
node/ip-192-168-62-4.ap-northeast-1.compute.internal     Ready    <none>   119m    v1.32.3-eks-473151a
node/ip-192-168-86-234.ap-northeast-1.compute.internal   Ready    <none>   3m36s   v1.32.3-eks-473151a

NAME                              READY   STATUS    RESTARTS   AGE
pod/load-generator                1/1     Running   0          5m32s
pod/php-apache-6487c65df8-6q7bc   1/1     Running   0          5m5s
pod/php-apache-6487c65df8-cvb2k   1/1     Running   0          5m5s
pod/php-apache-6487c65df8-jx2z7   1/1     Running   0          24m
pod/php-apache-6487c65df8-sf4g4   1/1     Running   0          4m50s
pod/php-apache-6487c65df8-w58fj   1/1     Running   0          5m5s
pod/php-apache-6487c65df8-x68sh   1/1     Running   0          109s
pod/php-apache-6487c65df8-xbw6f   1/1     Running   0          4m5s
pod/php-apache-6487c65df8-xfkdf   1/1     Running   0          4m5s
pod/php-apache-6487c65df8-xnhq5   1/1     Running   0          109s

NAME                                             REFERENCE               TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/php-apache   Deployment/php-apache   cpu: 41%/50%   1         10        9          116m

ここでは最終的にノードが2つに増え、アプリケーションのPodも全てRunningとなりCPU使用率が41%となりました。

Cluster AutoscalerのおかげでPending状態のPodを検知しノードを増やして無事Podを増設できました。
負荷を止めると次第にPodとノードが削除されるのが確認できると思います。

最後に

簡単な動作確認ではありますが、Horizontal Pod AutoscalerとCluster Autoscalerについてどなたかのイメージの手助けになれば幸いです。

参考

Amazon EKS – eksctl の使用を開始する - アマゾン EKS

Horizontal Pod Autoscalerウォークスルー | Kubernetes

autoscaler/cluster-autoscaler/cloudprovider/aws/README.md at master · kubernetes/autoscaler · GitHub