【Apache JMeter】負荷テスト実行用のdockerコンテナを作る

負荷テストを実施するにあたって、負荷テストを実行するためのdockerコンテナを作ることにした。
dockerコンテナを作った理由はとしては下記のとおり。

- どの環境でもコンテナを展開すればすぐに使える
- 状況に応じてdockerコンテナ間の通信上での負荷テストと、インターネット経由での負荷テストが切り替えやすい
- テストケースを入れ替えるだけで他のプロジェクトでも使える

特に今回はテスト対象となるシステムがAWS上で動いており、インターネット経由で負荷テストを実施するとCloudFront、WAF、ALBなどに大量のデータが行き交うことでコストが増大する可能性があったため、それらを経由せずにdockerコンテナ間で通信ができることが必要だった

（コスト計算した結果、100数円で済むことがわかったので最終的にはインターネット経由で実施した）

# docker file
```dockerfile
# イメージ
FROM openjdk:8-slim

# JMeterのバージョン指定
ARG JMETER_VERSION=5.6.3

# JMeterのダウンロードと解凍、不要ファイルの削除を一つのRUNコマンドで実行
# 事前のデータ投入をpythonスクリプトで実施するのでpythonもインストールしている
RUN apt-get update \
    && apt-get install -y wget tzdata python3-pip \
    && ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata \
    && wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz \
    && tar -xzf apache-jmeter-${JMETER_VERSION}.tgz \
    && rm apache-jmeter-${JMETER_VERSION}.tgz \
    && mv apache-jmeter-${JMETER_VERSION} /jmeter \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# PythonからMySQLへデータ投入するために必要なパッケージ
RUN pip3 install pymysql

# 環境変数の設定
ENV JMETER_HOME=/jmeter
ENV PATH=$JMETER_HOME/bin:$PATH

# 各種ファイルをコンテナにコピー
COPY *.jmx /.

# データ投入用のスクリプトをコピー
COPY data_insert.py /data_insert.py
COPY data_delete.py /data_delete.py

# データ登録→テスト実行→データ削除の順に実行
CMD /bin/sh -c 'python3 /data_insert.py && \
    TIMESTAMP=$(date +%Y%m%d-%H%M%S) && \
    jmeter -n -t /$JMX -l /report/results-$TIMESTAMP.jtl -e -o /report/report-$TIMESTAMP && \
    python3 /data_delete.py'

```

## 解説

```dockerfile
FROM openjdk:8-slim
```
JMeterを動作させるにはJava8以上が必要だったので、OpenJDK 8の軽量なDockerイメージを指定しています。

```dockerfile
RUN apt-get update \
    && apt-get install -y wget tzdata python3-pip \
    && ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata \
    && wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz \
    && tar -xzf apache-jmeter-${JMETER_VERSION}.tgz \
    && rm apache-jmeter-${JMETER_VERSION}.tgz \
    && mv apache-jmeter-${JMETER_VERSION} /jmeter \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*
```
RUNコマンドでは、JMeterをDLするためのwget、タイムゾーンをしているためのtzdata、事前データの投入と削除を行うスクリプトを実行するためのpython3をインストールしています。

その後、タイムゾーンの指定、JMeterのインストールをした後、不要なファイルの削除をしています。

```dockerfile
CMD /bin/sh -c 'python3 /data_insert.py && \
    TIMESTAMP=$(date +%Y%m%d-%H%M%S) && \
    jmeter -n -t /$JMX -l /report/results-$TIMESTAMP.jtl -e -o /report/report-$TIMESTAMP && \
    python3 /data_delete.py'
```
最後に、CMDで、データの登録、テストの実行、データの削除を順に実行するシェルスクリプトを指定しています。
テスト結果はタイムスタンプ付きのファイルに保存され、後で分析できるようにしています。

## その他
実行する時に通信先やデータ量、レポート出力先を変更できるようにDocker実行時に環境変数ファイルを指定している

```
docker run --env-file docker/stresstest/local.env  -v $(pwd)/report:/report my-stress-test
```
環境変数ファイルで定義した内容をJMeterに渡す場合は下記のように-Jをつけて実行する。
```dockerfile
CMD /bin/sh -c `jmeter -JAPI_BASE_URL="$API_BASE_URL" -n -t /$JMX -l /report/results-$TIMESTAMP.jtl -e -o /report/report-$TIMESTAMP`
```
上記の場合、環境変数ファイル内のAPI_BASE_URLがAPI_BASE_URLという名前でJMeterに渡される。

これをJMeterで扱うにはユーザー定義変数で${__P(API_BASE_URL)}とすれば取得できる

![スクリーンショット 2024-04-10 23.12.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/d08b29c0-eb22-144e-bf31-183f76a11f8f.png)