Kubernetes を使用した負荷分散のテスト

負荷テストは、実際のニーズに直面したときにシステムがどの程度適切に機能するかを示すため、どのようなバックエンド インフラストラクチャを開発する際にも鍵となる作業です。負荷テストで重要になるのは、アプリケーションを本番環境にデプロイする前に十分余裕を持って、ユーザーの行動とデバイスの動作を適切にシミュレートして懸念されるシステムのボトルネックを特定、把握することです。

しかし、専用のテスト インフラストラクチャは、継続的に必要とするものではないため、コストがかかり、メンテナンスが困難な場合があります。さらに、専用のテスト インフラストラクチャは、容量が固定された 1 回限りの設備投資となることが多いため、初期投資を超えた負荷テストの拡張が困難になり、テストが限られてしまうことがあります。その結果、開発チームの生産性が低下し、実稼働用にデプロイする前にアプリケーションが適切にテストされない可能性があります。

ソリューションの概要

クラウド コンピューティングを使用した負荷分散テストは、さまざまなテストシナリオにとって魅力的なオプションです。クラウド プラットフォームにより、高度な弾力性を備えたインフラストラクチャが提供されるため、シミュレートされた多数のクライアントでのアプリケーションとサービスのテストが容易になり、アプリケーションやサービスそれぞれに対してユーザーやデバイスの後にパターン化されたトラフィックが生成されます。さらに、クラウド コンピューティングの料金モデルは、負荷テストの非常に弾力性のある性質に合わせたモデルになっています。

アプリケーションの仮想マシン インスタンス全体を実行する代わりに軽量化を実現するコンテナは、シミュレートされたクライアントの迅速なスケーリングに最適です。コンテナは、軽量でデプロイしやすく、すぐに使えて特異なタスクに最適であるため、テスト用クライアントの実行に最適な抽象化を実現します。

Google Cloud Platform は、コンテナを使用した負荷分散テストに最適な環境です。このプラットフォームは、オープンソースのコンテナクラスタ マネージャである Kubernetes を活用した Google Kubernetes Engine(GKE)経由で、ファーストクラスのエンティティとしてコンテナをサポートします。GKE には、コンテナ インフラストラクチャとツールのプロビジョニングをすばやく行い、デプロイされたアプリケーションとリソースを管理する機能があります。

このソリューションでは、GKE を使用して負荷分散テスト フレームワークをデプロイする方法を示します。負荷分散テスト フレームワークでは、複数のコンテナを使用して、REST ベースのシンプルな API の負荷テスト トラフィックを作成します。このソリューションでは、シンプルなウェブ アプリケーションをテストしますが、同じパターンを使用して、ゲーム アプリケーションやモノのインターネット(IoT)アプリケーションなどのより複雑な負荷テストシナリオを作成することができます。ここでは、コンテナベースの負荷テスト フレームワークの一般的なアーキテクチャについて説明します。サンプル フレームワークの設定手順のチュートリアルについては、このドキュメントの最後にあるチュートリアル セクションをご覧ください。

このソリューションでは、負荷テスト トラフィックを作成するための GKE の使用に重点を置いて説明します。テスト対象システムは、REST API を使用するシンプルなウェブ アプリケーションです。このソリューションでは、既存の負荷テスト フレームワークを活用して、後述する API インタラクションをモデル化します。テスト対象システムをデプロイした後、このソリューションでは、Kubernetes Engine を使用して、負荷分散テストのタスクをデプロイします。

テスト対象システム

ソフトウェア テストの用語では、テスト対象システムは、テストが評価されるよう設計されているシステムのことです。このソリューションでのテスト対象システムは、Google App Engine にデプロイされているシンプルなウェブ アプリケーションです。このアプリケーションは、REST スタイルの基本的なエンドポイントを公開して、受信 HTTP POST リクエストをキャプチャします(受信データは永続化されません)。実際のシナリオでは、ウェブ アプリケーションは複雑で、キャッシュ、メッセージング、永続化などの多くの追加コンポーネントやサービスが含まれています。こうした複雑なアプリケーションは、このソリューションでは取り扱いません。Google Cloud Platform でのスケーラビリティの高いウェブ アプリケーションの構築に関する詳細については、スケーラビリティと復元性の高いウェブ アプリケーションの構築のソリューションをご覧ください。

サンプル アプリケーションのソースコードは、このドキュメントの最後にあるチュートリアルの一部として提供されています。

サンプルのワークロード

サンプル アプリケーションは、多くの IoT デプロイで見られるバックエンド サービス コンポーネントをモデルにして作成されています。バックエンド サービス コンポーネントでは、まずデバイスがサービスに登録し、次に指標やセンサー測定値の報告を開始するとともに、定期的にサービスに再登録するという一連のインタラクションが行われます。

次の図は、一般的なバックエンド サービス コンポーネントのインタラクションを示しています。

バックエンド サービス コンポーネントのインタラクションを示す図。

このインタラクションをモデル化するには、Locust を使用します。これは、複数のターゲットパスにまたがってリクエストを分散できる Python ベースの負荷テストツールです。たとえば Locust は、リクエストを /login/metrics のターゲットパスに分散できます。他にも JMeterGatlingTsung など、多くの負荷生成ソフトウェア パッケージがあり、プロジェクトのニーズに合わせて適切なものを選択できます。

ワークロードは、上記に説明したインタラクションに基づいており、Locust で一連のタスクとしてモデル化されます。実際のクライアントに近づけるために、各 Locust タスクが重み付けされます。たとえば、クライアントの合計リクエスト 1,000 個ごとに登録が 1 回発生します。

コンテナベースのコンピューティング

アーキテクチャの観点からすると、この負荷分散テスト ソリューションのデプロイに関係するのは、Locust コンテナ イメージとコンテナ オーケストレーションおよび管理メカニズムの 2 つのメイン コンポーネントです。

Locust コンテナ イメージとは、Locust ソフトウェアに含まれている Docker イメージです。Dockerfile は、関連付けられている Github レポジトリにあります(下記のチュートリアルをご覧ください)。Dockerfile はベースの Python イメージを使用し、Locust サービスを起動してタスクを実行するスクリプトを含んでいます。

このソリューションでは、コンテナ オーケストレーションおよび管理メカニズムとして GKE を使用します。オープンソース フレームワークの Kubernetes をベースにした GKE は、Google のあらゆるサービスで何年にもわたってコンテナのデプロイを実行、オーケストレーション、管理してきた実績のあるプロダクトです。コンテナベースのコンピューティングにより、デベロッパーは、ホスティング環境へのデプロイや統合ではなく、各自のアプリケーションに集中することができます。また、コンテナにより、負荷テストの移植が容易になるため、複数のクラウド環境でコンテナ化アプリケーションを実行できるようになります。GKE と Kubernetes では、コンテナのオーケストレーションと管理に固有のいくつかの概念を導入しています。

コンテナ クラスタ

コンテナ クラスタとは、アプリケーション全体の基盤となる Compute Engine インスタンスのグループです。GKE と Kubernetes のドキュメントでは、これらのインスタンスをノードと呼んでいます。クラスタは、1 つのマスターノードと 1 つ以上のワーカーノードで構成されます。マスターとワーカーはすべて、Kubernetes で実行されるため、コンテナ クラスタは Kubernetes クラスタと呼ばれることもあります。クラスタの詳細については、Kubernetes Engine のドキュメントをご覧ください。

ポッド

ポッドとは、同時にデプロイされる密結合したコンテナのグループです。一部のポッドには、コンテナが 1 つしか含まれていません。たとえば、このソリューションでは、各 Locust コンテナがそれ自身のポッドで実行されます。しかし、多くの場合、ポッドにはなんらかの方法で連携する複数のコンテナが含まれています。たとえば、このソリューションでは、Kubernetes は 3 つのコンテナが含まれているポッドを使用して、DNS サービスを提供します。1 つのコンテナでは、SkyDNS によって DNS サーバー機能が提供されます。SkyDNS は、別のコンテナにある etcd という名前の key-value ストアに依存しています。ポッドの 3 番目のコンテナでは、kube2sky が Kubernetes と SkyDNS 間の橋渡しとして機能します。

レプリケーション コントローラ

レプリケーション コントローラによって、指定した数のポッド「レプリカ」がどの時点でも確実に実行されます。ポッドレプリカが多すぎる場合は、レプリケーション コントローラによって一部のポッドが削除されます。ポッドレプリカが少なすぎる場合は、レプリケーション コントローラによってさらにポッドが起動されます。このソリューションには、3 つのレプリケーション コントローラがあります。1 つ目のレプリケーション コントローラは 1 つの DNS サーバーポッドの存在を確認し、2 つ目のレプリケーション コントローラは 1 つの Locust マスターポッドを保持し、3 つ目のレプリケーション コントローラは実行されているちょうど 10 個の Locust ワーカーポッドを保持しています。

サービス

更新やメンテナンスのノードの障害や意図的なノードの中断などのさまざまな理由で、特定のポッドが表示されないことがあります。これは、ポッドの IP アドレスによってそのポッドに信頼できるインターフェースが提供されないことを意味します。より信頼性の高いアプローチでは、インターフェースの変更されない抽象表現を使用し、基になるポッドが表示されず、IP アドレスが異なる新しいポッドに置き換えられる場合でも、インターフェースが提供されるようにしています。GKE サービスでは、ポッドの論理セットとポッドへのアクセス ポリシーを定義することで、このような抽象インターフェースを提供します。このソリューションでは、ポッドやポッドのセットを表すいくつかのサービスがあります。たとえば、DNS サーバーポッドのサービス、Locust マスターポッドのサービス、10 個すべての Locust ワーカーポッドを表すサービスがあります。

次の図は、マスターノードとワーカーノードの内容を示してします。

マスターノードとワーカーノードの内容を示す図。

テスト対象システムのデプロイ

このソリューションでは、App Engine を使用してテスト対象システムを実行します。テスト対象システムをデプロイするには、Cloud SDK をインストールして実行できるための有効な Google Cloud Platform アカウントが必要です。SDK をインストールして実行すると、1 つのコマンドでサンブルのウェブ アプリケーションをデプロイできます。このウェブ アプリケーションのソースコードは、このドキュメントの最後にあるチュートリアルの一部として提供されています。

負荷テストのタスクのデプロイ

負荷テストのタスクをデプロイするには、最初に負荷テストのマスターをデプロイし、10 個の負荷テストワーカーからなるグループをデプロイします。この多数の負荷テストワーカーを使用し、かなりの量のテスト用トラフィックを作成できます。ただし、外部システムへのトラフィックを多く生成しすぎると、DoS 攻撃と見なされる可能性があるので注意してください。Google Cloud Platform 利用規約Google Cloud Platform 利用規定ポリシーをご確認ください。

負荷テストのマスター

デプロイの最初のコンポーネントは、Locust のマスターです。このマスターは、前述の負荷テストのタスクを実行するためのエントリ ポイントです。必要となるマスターは 1 つだけであるため、Locust のマスターは、レプリカが 1 つのレプリケーション コントローラとしてデプロイされます。レプリケーション コントローラは、高可用性を確保する理由で 1 つのポッドをデプロイする場合にも役立ちます。

レプリケーション コントローラの構成により、コントローラの名前(locust-master)、組織のラベル(name: locust, role: master)、コンテナによって公開される必要があるポート(ウェブ インターフェースの場合は 8089、ワーカーとの通信の場合は 55575558)などのいくつかの要素が指定されます。この情報は、Locust ワーカー コントローラを構成するために後で使用されます。次のスニペットには、ポートの構成が含まれています。

...
ports:
  - name: locust-master-web
    containerPort: 8089
    protocol: TCP
  - name: locust-master-port-1
    containerPort: 5557
    protocol: TCP
  - name: locust-master-port-2
    containerPort: 5558
    protocol: TCP

次に、サービスをデプロイして、公開されたポートがクラスタ内の hostname:port で他のポッドにアクセスでき、わかりやすいポート名で参照できるようにします。サービスを使用すると、マスターが失敗してレプリケーション コントローラで新しいポッドに置き換えられる場合でも、Locust のワーカーが簡単にマスターを検出し、確実にマスターと通信できるようになります。また、Locust マスター サービスには、クラスタレベルで外部転送ルールを作成するディレクティブも含まれています。これにより、外部トラフィックがクラスタ リソースにアクセスできる機能が提供されます。ターゲット インスタンスへの完全なアクセス権を提供するには、ファイアウォール ルールを作成する必要があります。

Locust マスターをデプロイした後、外部転送ルールのパブリック IP アドレスを使用してウェブ インターフェースにアクセスできます。Locust ワーカーをデプロイした後、シミュレーションを開始して Locust ウェブ インターフェース経由で集計した統計情報を確認できます。

負荷テストのワーカー

デプロイの次のコンポーネントには、前述の負荷テストのタスクを実行する Locust ワーカーが含まれています。Locust ワーカーは、10 個のポッドを作成する 1 つのレプリケーション コントローラによってデプロイされます。ポッドは、Kubernetes クラスタ全体に分散されます。各ポッドでは、環境変数を使用して、テスト対象システムのホスト名、Locust マスターのホスト名などの重要な設定情報を制御します。ワーカーのレプリケーション コントローラの設定は、下記のチュートリアルにあります。その設定には、そのコントローラの名前(locust-worker)、組織のラベル(name: locust, role: worker)、前述の環境変数が含まれています。次のスニペットには、名前、ラベル、レプリカ数の設定があります。

kind: ReplicationController
  apiVersion: v1
  metadata:
    name: locust-worker
    labels:
      name: locust
      role: worker
  spec:
    replicas: 10
    selector:
      name: locust
      role: worker
...

Locust ワーカーでは、ワーカーポッド自体で通信の受信をサポートする(つまり、Locust マスターポッドに直接接続する)必要がないため、追加サービスをデプロイする必要はありません。

次の図は、Locust マスターと Locust ワーカー間の関係を示しています。

Kubernetes のポッドと Locust のマスターノードおよびワーカーノードを示す図。

レプリケーション コントローラによる Locust ワーカーのデプロイの後、Locust マスターのウェブ インターフェースに戻ってデプロイされたワーカー数に対応するスレーブ数を確認できます。

負荷テストのタスクの実行

負荷テストの開始

Locust マスターのウェブ インターフェースでは、次の画像に示すようにテスト対象システムに対して負荷テストのタスクを実行できます。

最初に表示される Locust のウェブ インターフェースのスクリーンショット。

開始するには、シミュレートするユーザーの合計数と各ユーザーを生成する速度を指定します。次に、[スワーミングの開始] をクリックしてシミュレーションを開始します。時間の経過とともにユーザーが生成されるにつれ、次の画像に示すように統計情報でリクエスト数、1 秒あたりのリクエスト数などのシミュレーション指標の集計が開始されるのがわかります。

スワーミングが進行しているときの Locust ウェブ インターフェースのスクリーンショット。

シミュレーションを停止するには、[停止] をクリックすると、テストが終了します。全体の結果は、スプレッドシートにダウンロードできます。

クライアントのスケーリング

シミュレート対象のユーザー数をスケールアップするには、Locust ワーカーポッド数を増やす必要があります。Locust ワーカー コントローラで指定されているように、レプリケーション コントローラによって 10 個の Locust ワーカーポッドがデプロイされています。レプリケーション コントローラによってデプロイされるポッド数を増やすために、ポッドを再デプロイすることなくコントローラのサイズを変更できる機能が Kubernetes に用意されています。たとえば、kubectl コマンドライン ツールを使用してワーカーポッド数を変更できます。次のコマンドにより、ワーカーポッドのプールが 20 にスケーリングされます。

$ kubectl scale --replicas=20 replicationcontrollers locust-worker

scale コマンドの発行後、すべてのポッドがデプロイされ、起動するまで数分かかります。すべてのポッドが起動したら、Locust マスターのウェブ インターフェースに戻って負荷テストを再開します。

リソースと費用

このソリューションでは、4 つの GKE ノードを使用します。これらのノードはそれぞれ、n1-standard-1 タイプの Compute Engine VM 標準インスタンスを基盤としています。このコンテナ クラスタを 1 か月実行した場合の費用は、GCP 料金計算ツールを使用して見積もることができます。前述のように、コンテナ クラスタのサイズはお客様のニーズに合わせてスケーリングされるようにカスタマイズ可能です。料金計算ツールで、クラスタの特性をカスタマイズして、スケールアップやスケールダウンした場合の費用を見積もることができます。

次のステップ

ここでは、GKE を使用してシンプルなウェブ アプリケーション向けの負荷テスト フレームワークを作成する方法を説明しました。GKE では、負荷テスト フレームワークの基盤となるコンテナノードの数を指定できます。また、負荷テストワーカーをポッドにまとめたり、GKE で実行し続けるポッドの数を宣言したりすることもできます。

ここで紹介したものと同じパターンを使えば、さまざまなシナリオやアプリケーションに適応した負荷テスト フレームワークを作成できます。たとえば、これと同じパターンで、メッセージング システム、データ ストリーム管理システムや、データベース システムの負荷テスト フレームワークを作成できます。また、新しい Locust タスクを作成したり、別の負荷テスト フレームワークを作成したりすることも可能です。

このソリューションで示したフレームワークを拡張するもう 1 つの方法は、収集される指標をカスタマイズすることです。それによって、たとえば、1 秒あたりのリクエスト数の測定、負荷の増加に伴うレスポンスのレイテンシのモニタリング、レスポンスの失敗率とエラーのタイプの確認を行うフレームワークも作成できます。また、Stackdriver Monitoring のように利用可能なモニタリング オプションもいくつかあります。

チュートリアル

手順、ソースコードなど、チュートリアルのすべての内容は、GitHub の https://github.com/GoogleCloudPlatform/distributed-load-testing-using-kubernetes で入手できます。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...