AWS Fargateにデプロイしたアプリに対して負荷テストを行う

2022.03.07

Introduction

先日Fargateで起動したWebアプリに対して負荷テストを実行していたので、
環境の構築方法についての備忘録です。  

本稿ではNodeのWebアプリをFargateで起動し、AWSでの分散負荷テストソリューションを    つかって構築した環境から負荷テストを実行するまでを記述します。

Environment

以下の環境で試しました。 aws cliは実行可能な前提です。

  • OS : MacOS 11.3.1
  • Node: 16.2
  • Docker : 20.10.12

Build Services

負荷テスト環境を構築

ここにある負荷分散テストソリューションを使えば、
かんたんに環境が構築可能です。
cloudformationテンプレートが公開されているので、これを使ってデプロイするだけで
負荷テストを実行する環境が全部できてしまいます。

さらに、使用方法や具体的な構築方法もデプロイガイドがありますし、
ここにはやってみた記事もあります。

実際に私もこれらを参考に負荷テスト実行環境を作成しました。
(1時間もかからず構築完了)

次に負荷テスト対象となるWebアプリを構築します。

Webアプリをローカルで作成

まずはNodeアプリをローカルで作成します。
npmやyarnでfastifyをインストールしましょう。

% mkdir path/rour/node-apps && cd path/rour/node-apps
% npm init #すべてデフォルトでOK
% npm install --save fastify

package.jsonのscriptsに起動用コマンドを追記します。

{
  "name": "node-apps",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "fastify": "^3.25.0"
  }
}

アクセスすると固定文字列を返すだけのAPIを定義します。

//index.js
const fastify = require('fastify')({ logger: true })

fastify.get('/', async (request, reply) => {
  return "ok";
})

const start = async () => {
  try {
    await fastify.listen(8080,'0.0.0.0')
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}
start()

npm startで起動。

%  npm start

> node-apps@1.0.0 start
> node index.js

{"level":30,"time":1646630037763,"pid":91885,"hostname":"XXXX.local","msg":"Server listening at http://0.0.0.0:8080"}

アクセス確認OKです。

% curl http://localhost:8080
ok

アプリをFargateで動かす

Fargateで動かすために、さきほどのアプリをdocker image化して
ECRへpushします。
まずはDockerfileを作成しましょう。

#Dockerfile
FROM --platform=linux/amd64 node:16-alpine
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 8080
CMD [ "node", "index.js" ]

私の環境がM1 macなので--platformオプションが必要でした。
(intel macとかwinならFROM node:16-alpineでよいと思われる)

特に変わったとこはやってません。
ファイルコピーとnpmモジュールのインストール、
あとは公開ポートの設定とアプリの起動です。

buildコマンドでdocker imageの作成。

% docker build . -t node-apps

dockerイメージができたので、次はECRにリポジトリを作成してpushします。
まずはリポジトリを作成しましょう。

% aws ecr create-repository --repository-name <リポジトリ名> --region <リージョン>

成功すればリポジトリ情報が返ってきます。
repositoryUriをおぼえておきましょう。

イメージをpushする前にget-login-passwordでログインしておきます。

% aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com

適当にタグ付け。

% docker tag node-apps:latest  <AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com/node-apps:v1

からのpush

% docker push <AWSアカウントID>.dkr.ecr.<リージョン>.amazonaws.com/node-apps:v1

これでECRにイメージがpushされました。
https://<リージョン>.console.aws.amazon.com/ecr/repositories
の(さきほど作成した)リポジトリをクリックすると、pushしたイメージを確認することができます。

その後、ここ
Create ECS Cluster and define Task Definition
にあるとおり、コマンドラインでクラスタの作成からタスクの作成をやってもいいし、
AWSコンソールからポチポチとクラスタ作成とタスク定義(とサービス定義)をやってもよいです。
※セキュリティグループのポート開放(今回なら8080ポート)を忘れずに

タスクが起動したら詳細画面からアクセス用のエンドポイント(publicip)を確認しておきましょう。

テスト実行

さきほど構築した負荷テスト環境の情報が任意のメールアドレス宛にきているので、
その情報(Username、Password、ConsoleのURL)をつかってログインします。

CREATE TESTボタンを押し、下記項目を設定してRUN NOWボタンを押せばテストが開始されます。   

項目 内容 備考
Name 負荷テストの名前
Descriptio テストシナリオの説明
Task Count 起動するDockerコンテナの数 Max 100
Concurrency タスクあたりの同時接続数 Max 200
Ramp up 同時接続数に達するまでの時間
Hold For 同時接続数を維持する時間
Test Type シンプルテスト or JMater
HTTP endpoint under test ターゲットのURL シンプルテストの場合
HTTP Method HTTPメソッド シンプルテストの場合
HTTP Headers HTTPヘッダ シンプルテストの場合はオプション
Body Payload メッセージボディ シンプルテストの場合はオプション

テストが終わると結果レポートが表示されます。
また、実行中のメトリクスをCloudwatchで確認することもできます。

Summary

今回はAWS負荷テストソリューションを使った環境構築、
FargateをつかったNodeアプリのデプロイを解説しました。
これで負荷テストも手軽にできますね。