負荷試験を⾏う際に、⼩規模であればあまり気にする必要はないと思いますが、中〜⼤規模になってくると、負荷掛け環境にも⾼い性能が求められるケースがあります。
しかし、事前にどのくらいの性能が必要かを予想するのは難しいため、⾃動スケーリングでリソースを確保できたら楽ですよね。

Google Cloudでは、そのような場合に備えた負荷掛け環境をGKEを⽤いて構築する⽅法が紹介されています。
Google Kubernetes Engine を使⽤した負荷分散テスト

今回は、この⼿順に沿って実際に負荷掛け環境を構築していきます。

仕組み

構成は以下のようになっています。

Locustの画⾯操作とモニタリングはマスターポッドで処理され、内部TCP/UDPロードバランサを通して、ウェブ上で確認できます。
ワーカーポッドは負荷試験対象へのリクエストを⽣成するため、リクエスト数を増やすほどにワーカーポッドの台数も必要になります。
また、ポート8089はLocustのウェブインターフェース⽤に使⽤し、ポート5557, 5558はポッドへの通信のために使⽤しています。

前提条件

  • 下記APIの有効化
    • App Engine
    • Artifact Registry
    • Cloud Build
    • Compute Engine
    • Resource Manager
    • Google Kubernetes Engine
    • Identity and Access Management
  • 下記権限の付与
    • Service Usage 管理者
    • Kubernetes Engine 管理者
    • App Engine 管理者
    • App Engine 作成者
    • Artifact Registry 管理者
    • プロジェクト IAM 管理者
    • Compute インスタンス管理者(v1)
    • サービス アカウント ユーザー
    • Cloud Build サービス アカウント
    • サービス アカウント管理者
  • 負荷試験ツール:Locust
  • Locustアプリケーション⽤コンテナイメージ:distributed-load-testing-using-kubernetes

設定⽅法

GKEクラスタ作成

1.GKEにアタッチするサービスアカウントを以下の権限で作成

  • Artifact Registry 読み取り
  • Kubernetes Engine ノード サービス エージェント

2.GKEクラスタを作成

gcloud container clusters create 【GKEクラスタ名】 \
--service-account=【作成したサービスアカウント】 \
--region 【リージョン】 \ #asia-northeast1
--network=【VPC名】
--subnetwork=【サブネット名】
--machine-type 【ノードに使⽤するマシンタイプ】 \ #e2-standard-4
--enable-autoscaling \
--num-nodes 3 \
--min-nodes 3 \
--max-nodes 10 \
--scopes "【スコープのURI】" #クラウドプラットフォーム(https://www.googleapis.com/auth/cloud-platform)

3.GKEクラスタに接続

gcloud container clusters get-credentials 【GKEクラスタ名】 \
   --region 【リージョン】 \
   --project 【プロジェクト名】

以下のように出⼒されればOKです。

Fetching cluster endpoint and auth data.
kubeconfig entry generated for 【GKEクラスタ名】.

補⾜1

GKEクラスタを作成する際に、レガシーネットワークを指定していると下記のエラーが発⽣します。
––no-enable-ip-aliasを付けることでエラーは回避できますが、エイリアスIPを使⽤したい場合は、レガシーネットワークを使わないようしましょう。

  • ResponseError: code=400, message=IP aliases cannot be used with a legacy network.

コンテナイメージのビルド

1.GitHubからサンプルリポジトリをクローン

git clone https://github.com/GoogleCloudPlatform/distributed-load-testing-using-kubernetes

2.作業ディレクトリを移動

cd distributed-load-testing-using-kubernetes

3.Artifact Registryにリポジトリを作成

gcloud artifacts repositories create 【Artifact Registryリポジトリ名】 \
    --repository-format=docker  \
    --location=【リージョン】 \
    --description="Distributed load testing with GKE and Locust"

4.コンテナイメージをビルド

gcloud builds submit \
    --tag 【リージョン】-docker.pkg.dev/【プロジェクト名】/【Artifact Registryのリポジトリ名】/【コンテナイメージ名】:【イメージタグ】 \
    docker-image

5.イメージがArtifact Registryに保存されたことを確認

gcloud artifacts docker images list 【リージョン】-docker.pkg.dev/【プロジェクト名】/【Artifact Registryのリポジトリ名】 | grep 【コンテナイメージ名】

以下が出力されればOKです。

Listing items under project 【プロジェクト名】, location 【リージョン】, repository 【Artifact Registryのリポジトリ名】.
IMAGE: 【リージョン】-docker.pkg.dev/【プロジェクト名】/【Artifact Registryのリポジトリ名】/【コンテナイメージ名】

docker-image/locust-tasks/tasks.py

サンプルアプリケーションは、/loginと/metricsへのリクエストを1:999の割合でテストするアプリケーションとなっています。

class MetricsTaskSet(TaskSet):
    _deviceid = None

    def on_start(self):
        self._deviceid = str(uuid.uuid4())

    @task(1)
    def login(self):
        self.client.post(
            '/login', {"deviceid": self._deviceid})

    @task(999)
    def post_metrics(self):
        self.client.post(
            "/metrics", {"deviceid": self._deviceid, "timestamp": datetime.now()})

class MetricsLocust(FastHttpUser):
    tasks = {MetricsTaskSet}

GKEのマスターポッドとワーカーポッドのデプロイ

1.以下のファイルのパラメータを編集

vi kubernetes-config/locust-master-controller.yaml.tpl
vi kubernetes-config/locust-worker-controller.yaml.tpl
  • image:【リージョン】-docker.pkg.dev/【プロジェクト名】/【Artifact Registryのリポジトリ名】/【コンテナイメージ名】
  • Target_Host:http://【負荷試験対象のFQDN】
  • その他、必要に応じてポッド数などを調整する

2.マスターデプロイメント、およびワーカーデプロイメントを作成

envsubst < kubernetes-config/locust-master-controller.yaml.tpl | kubectl apply -f -
envsubst < kubernetes-config/locust-worker-controller.yaml.tpl | kubectl apply -f -
envsubst < kubernetes-config/locust-master-service.yaml.tpl | kubectl apply -f -

3.デプロイメントが作成されたことを確認

kubectl get pods -o wide

以下のように出力されればOKです。

NAME                             READY   STATUS    RESTARTS   AGE   IP          NODE                                             NOMINATED NODE   READINESS GATES
locust-master-77c8784dd7-pgclg   1/1     Running   0          73s   10.44.7.6   gke-kameda-test-gke-default-pool-1f1a4018-d95t   <none>           <none>
locust-worker-86854fbf74-4zfw4   1/1     Running   0          58s   10.44.8.2   gke-kameda-test-gke-default-pool-1f1a4018-d5gq   <none>           <none>
locust-worker-86854fbf74-hbmbb   1/1     Running   0          58s   10.44.6.3   gke-kameda-test-gke-default-pool-1f1a4018-sw5f   <none>           <none>
locust-worker-86854fbf74-np4bn   1/1     Running   0          58s   10.44.2.4   gke-kameda-test-gke-default-pool-f1d133a3-h4ms   <none>           <none>
locust-worker-86854fbf74-vtrvj   1/1     Running   0          58s   10.44.3.4   gke-kameda-test-gke-default-pool-f7ba5e2f-1n03   <none>           <none>
locust-worker-86854fbf74-wfkm7   1/1     Running   0          58s   10.44.0.3   gke-kameda-test-gke-default-pool-f1d133a3-8t4s   <none>           <none>

4.サービスを確認

kubectl get services

以下のように出力されればOKです。
後ほど、locust-master-webのEXTERNAL-IPの値でLocustアプリケーションへ接続します。

NAME                TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
kubernetes          ClusterIP      10.48.0.1      <none>        443/TCP             23m
locust-master       ClusterIP      10.48.12.154   <none>        5557/TCP,5558/TCP   102s
locust-master-web   LoadBalancer   10.48.5.48     10.10.10.17   8089:30780/TCP      102s 

Locustアプリケーションへ接続

内部ロードバランサを立てているため、同じネットワーク内からは接続できますが、インターネットから接続することはできません。
そのため、プロキシ用GCEを作成し、SSHトンネルを使用して接続します。

  1. プロキシ用GCEを作成
gcloud compute instances create-with-container 【GCE名】 \
--zone 【ゾーン】 \
--network 【VPC名】 \
--subnet 【サブネット名】 \
--container-image gcr.io/cloud-marketplace/google/nginx1:latest \
--container-mount-host-path=host-path=/tmp/server.conf,mount-path=/etc/nginx/conf.d/default.conf \
--metadata=startup-script="#! /bin/bash
 cat <<EOF  > /tmp/server.conf
 server {
     listen 8089;
     location / {
         proxy_pass http://【locust-master-webのEXTERNAL-IP】:8089;
     }
 }
EOF"

2.(開いてない場合は)マネジメントコンソール右上のアイコンからCloud Shellを開く

3.プロキシ用GCEへのSSHトンネルを開く

gcloud compute ssh --zone 【ゾーン】 【GCE名】 -- -N -L 8089:localhost:8089

4.Cloud Shellターミナルの右上のアイコンから、[ウェブでプレビュー]をクリック

5.[ポートを変更]を選択し、値に8089と入力

6.ブラウザでLocustのページが表示されればOK

終わりに

GKEとサンプルコンテナイメージを利用して、Locustアプリケーションをデプロイできました。
私は今回初めてGKEを触ったので、詳細設定についてはわかっていない部分が多いのですが、それでもこんなに簡単に負荷掛け環境を構築できることに非常に驚きました。
また、Cloud Monitoringでリクエスト数の増減やレイテンシなどを確認すれば、Google Cloud内で全てを完結させることも可能です。

参考
Google Kubernetes Engine を使用した負荷分散テスト