EKS Auto Mode環境でHPAを使ってPodを自動スケーリングする

はじめに

こんにちは。hiranoです。
以前の記事「Amazon EKS Auto Mode+CloudShellで最短コンテナ公開」では、EKS Auto Modeで作成したクラスターにnginxをデプロイし、Service type LoadBalancerを使ってNLB経由で外部公開する流れを確認しました。

今回はその応用編として、EKS Auto Mode環境でHPA(Horizontal Pod Autoscaler)を使い、Pod数を自動で増減させる方法を確認します。

HPAとは、Kubernetesに用意されている自動スケーリング機能の1つであり、Deploymentなどで管理されているPodのCPU使用率などをもとに、必要に応じてPod数を自動的に増減させます。

たとえば、アプリケーションへのアクセスが増えてCPU使用率が高くなった場合、HPAはDeploymentのreplicas数を増やし、より多くのPodでリクエストを処理できるようにします。
反対に、負荷が下がった場合はPod数を減らし、必要以上にリソースを使わないように調整します。

要は、アプリケーションの負荷に応じてPod数を自動調整したい場合に使うということです。

これらを踏まえて、冒頭に記載した記事で作成したEKS Auto Mode環境をベースに、新たにアプリケーションをデプロイし、負荷をかけたときにPod数が自動で増えること、負荷を止めたあとにPod数が減ることを見ていきます。

前提・準備

本記事では、以下の状態を前提とします。

・EKS Auto Modeで作成したクラスターが存在していること
・CloudShellからkubectlでEKSクラスターへ接続できること
 ※コマンドは基本的にCloudShellから実行します。
kubectl get nodesでNode情報を確認できること

HPAの動作を確認するため、nginxではなくHPA検証用のサンプルアプリケーションを新しくデプロイします。
※作成物の命名はブログ用のサンプルになります。

また、HPAはPodのCPU使用率などのメトリクスをもとにスケーリングを行うため、Metrics Serverが利用できる状態になっている必要があります。
Metrics Serverが利用できるかどうかは、後続の手順で確認します。

なお、今回もService type LoadBalancerを使ってNLB経由でアプリケーションを外部公開します。
ただし、料金面や不要な外部トラフィックを考慮し、HPAの負荷検証ではNLBへ大量アクセスを流すのではなく、クラスター内部の負荷生成用PodからService宛にアクセスしていくことにします。

それでは、次章から実践編です。

実践

1. EKSクラスターとMetrics Serverを確認

まずは、CloudShellからEKSクラスターへ接続できていることと、HPAで利用するPodやNodeのメトリクスを取得できる状態になっているかを確認します。
HPAは、PodのCPU使用率などをもとにスケーリングを行いますが、HPA自身が直接PodのCPU使用率を取得するわけではありません。
Kubernetesでは、Metrics Serverが各NodeやPodのCPU・メモリ使用量を収集し、HPAはそのメトリクスを参照してスケーリングを判断します。
そのため、HPAを利用するにはMetrics Serverが利用できる状態になっている必要があります。

コマンドと確認ポイント

# EKSクラスターへの接続状態とメトリクス取得状況を確認
kubectl config current-context
kubectl get nodes
kubectl top nodes
kubectl top pods


kubectl config current-contextで、念のため、どのKubernetesクラスターへ向けて実行されるかを確認しています。
kubectl get nodesで、NodeのSTATUSReadyになっていれば、EKSクラスターへ接続できています。
また、kubectl top nodeskubectl top podsでCPUやメモリ使用量が表示されれば、Metrics Serverが利用できています。

なお、kubectl top podsについては、default namespaceにPodが存在しない場合、上記のように「No resources found in default namespace.」と表示されることがありますが、kubectl top nodesでNodeのCPU・メモリ使用量が確認できていれば、Metrics Serverは利用できていると判断して問題ないです。

★補足
もし、「error: Metrics API not available」のように表示される場合は、Metrics Serverがまだ利用できない状態です。
以下のコマンドでMetrics Serverをインストールする必要があります。

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

インストール後、少し待ってから再度kubectl top nodeskubectl top podsを実行し、CPUやメモリ使用量が表示されることを確認できれば、HPAを利用する準備完了です。
 

2. HPA検証用アプリのデプロイ

次に、HPAの動作確認に使用するサンプルアプリケーションをデプロイします。
今回は、Kubernetes公式チュートリアルでも使用されているサンプルイメージregistry.k8s.io/hpa-example(PHP + Apache構成のHPA検証用サンプルアプリケーション)を利用します。
nginxのイメージを使用してもいいのですが、nginxは軽量で静的なレスポンスを返すだけで、CPU負荷を上げづらい場合があるためです。

では、デプロイするためにDeploymentとServiceをYAMLファイルで定義して作成します。
DeploymentではHPAがCPU使用率を計算できるように、Podが必要とするCPUリソースの目安であるCPU request200m(0.2CPU)と設定します。
また、Serviceは前回と同様にtype: LoadBalancerとし、NLB経由で外部からアクセスできるようにします。

コマンドと確認ポイント

# 作業ファイル整理のため、作業用ディレクトリを作成して移動
mkdir -p ~/eks-hpa-demo
cd ~/eks-hpa-demo

# DeploymentとServiceを定義するYAMLファイルを作成
vi php-apache.yaml
# php-apache.yamlの中身
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php-apache
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    service.beta.kubernetes.io/aws-load-balancer-subnets: "<サブネットID>,<サブネットID>"
spec:
  type: LoadBalancer
  selector:
    app: php-apache
  ports:
  - port: 80
    targetPort: 80
# 作成したYAMLファイルを適用
kubectl apply -f php-apache.yaml

# Deployment、Service、Podが作成されたことを確認
kubectl get deployment php-apache
kubectl get pods
kubectl get service php-apache


kubectl get deployment php-apache で、DeploymentのREADY1/1になっていれば、Podが起動しています。
kubectl get pods では、php-apacheのPodがRunningになっていることを確認します。
また、kubectl get service php-apache では、ServiceのTYPELoadBalancerになっていることと、EXTERNAL-IPにNLBのDNS名が表示されることを確認しましょう。

ブラウザまたはcurlでhttp://<NLBのDNS名>にアクセスし、「OK!」と表示されれば問題なしです。

3. HPAの作成

それでは、先ほど作成した php-apache Deploymentを対象にHPAを作成します。

HPAでは、最小Pod数、最大Pod数、スケーリングの基準となるCPU使用率を指定します。
ここでは、CPU使用率が50%を超えるとPod数を増やす(min:1,max:10)ように設定してみます。
現状はCPU request200mに設定されているので、100m=50% ということになりますね。

コマンドと確認ポイント

# php-apache Deploymentに対してHPAを作成
kubectl autoscale deployment php-apache \
--cpu-percent=50 \
--min=1 \
--max=10

# HPAが作成されたことを確認
kubectl get hpa

# HPAの詳細を確認
kubectl describe hpa php-apache


kubectl get hpaTARGETS で、現在のCPU使用率と目標値を確認できます。
左側が現在のCPU使用率、右側がHPAで設定した目標CPU使用率です。

kubectl describe hpa php-apache では、HPAの詳細やイベントを確認できます。
スケーリング条件や現在のPod数、イベントにエラーが出ていないことを確認します。
なお、ScalingLimitedFalse になっていますが、DesiredWithinRange と表示されている場合、HPAが計算したPod数が minmax の範囲内に収まっていることを示しているだけなので、エラーではないです。

ここまで確認できれば、HPAの作成は完了です。

★補足
HPAの作成直後は、kubectl get hpaTARGETS<unknown>/50% と表示される場合があります。
これは、Metrics Serverからメトリクスを取得するまでに少し時間がかかるためです。
しばらく待ってから、再度コマンドを実行すると正常にCPU使用率が表示されます。  
 

4. スケーリング状況の確認

最後に、HPAによってPod数が自動で増減することを確認します。
前提にて記載したとおり、NLBへ大量アクセスを流すのではなく、クラスター内部に負荷生成用Podを起動し、Service名 php-apache 宛にアクセスします。

ここでは、負荷生成用Podとして load-generator という一時的なPodを起動します。
このPodはHPAの対象ではなく、php-apache Serviceへ継続的にアクセスして負荷をかけるためのPodです。
--rm を指定しているため、Pod内のシェルを終了すると、このPodは自動的に削除されます。

コマンドと確認ポイント

# 負荷をかける前のHPAとPod数を確認
kubectl get hpa
kubectl get pods

# 負荷生成用Podを起動
kubectl run -i --tty load-generator \
--rm \
--image=busybox:1.28 \
--restart=Never \
-- /bin/sh

# Service宛に継続的にアクセスして負荷をかける
while true; do wget -q -O- http://php-apache; done

# 負荷生成を停止
Ctrl + C
exit

# 負荷をかけた後のHPAとPod数を確認
kubectl get hpa
kubectl get pods

負荷をかけた後に、kubectl get hpa では、TARGETS が上がり、 REPLICASが増えています。
CPU使用率が目標値を超えると、HPAがDeploymentのreplicas数を増やし、その結果として、REPLICAS の値が増え、kubectl get pods でも php-apache のPod数が増えていくことを確認できます。

負荷を止める場合は、負荷生成用Podを実行しているターミナルで Ctrl + C を押し、その後 exit でPodから抜けます。
止まったあと、しばらくするとHPAがPod数を最小値に戻ります。

★補足
スケールアウトやスケールインには少し時間がかかるため、すぐにPod数が増減しない場合があります。
特にスケールインは安定化のため、負荷が下がってから反映されるまで時間がかかることが多いです。

まとめ

今回は、EKS Auto Mode環境をベースに、HPAを使ったスケーリングを確認しました。
実際の構成ではALBやNLBなどを経由して外部からアクセスが増えるケースもありますが、実践編では、NLBへの大量アクセスを避けるため、クラスター内部から負荷をかけました。
これにより、外部公開の構成を維持しつつ、HPAによるPod数の増減を確認できました。

HPAを利用するには、PodのCPU使用率などのメトリクスを取得できる状態になっている必要があります。
そのため、事前にMetrics Serverが利用できることを確認しておくことが重要です。

改めてとなりますが、HPAはNodeやサーバーを直接増減させるものではなく、Deploymentのreplicas数を調整してPod数を増減させる仕組みとなります。
EKS環境でアプリケーションの負荷に応じてPod数を自動調整したい場合に、有効な選択肢の1つだということが分かりましたね。

おまけ
作成したリソースを削除したい場合は、以下のコマンドを参考にしてみてください。

# HPAを削除
kubectl delete hpa php-apache

# DeploymentとServiceを削除
kubectl delete -f php-apache.yaml

以上、ご覧いただきありがとうございました。