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