はじめに
k6用のプロジェクトテンプレートを作成したので、紹介します。
いざ負荷試験のスクリプトを作り始めるとなった際に、色々と整備して初期構築をするのも大変です。
- 複数のシナリオと、そのシナリオを束ねるシナリオセットはどう管理する?
- 負荷試験対象の環境情報(local, stg, etc…)を簡単に切り替えられうようにしたい
- シナリオの設定値(VU、イテレーション数等)は簡単に渡せるようにしたい
- コードフォーマットはなるべく統一させたい 等
- 自分なりに考えた良さげな構成を紹介する
ベースとなるプロジェクトを整備するだけでも大変なものです。
今回は、試行錯誤しつつ導き出した自分なりの良さげな構成例を紹介します。
チュートリアル上、エラーとなる箇所がある場合には、最新のリポジトリのソースをご覧ください。 https://github.com/gonkunkun/k6-template
想定する読者
- これから、k6を使って負荷試験のスクリプトの準備を始めようとしている人
- k6で開発を進める上でのテンプレート構成を知りたい人
クイックスタート
本テンプレートは、以下の前提を想定しています
- k6はローカルやEC2等のインスタンス上で動作する想定
- goやbrewの環境は既に準備されている想定
テンプレートは以下のリポジトリからダウンロード出来ます。
https://github.com/gonkunkun/k6-template
それではまずは、テンプレートをダウンロードしてきて、スモークテスト用のシナリオを動かすところまで進めてみましょう。
ここまで出来たら、環境構築終了です。
実際にシナリオを動かしてみましょう。
以下のようなログが流れればひとまず成功ですね。
本プロジェクト構成の紹介
ただ単に手順に沿ってk6を動かしただけだと、中身がよく分からないですね。
ここからは、設定内容や意図をお伝えしていきます。
やりたかったことは以下の通り。
- 個々のシナリオとユースケース毎のシナリオセットを綺麗に管理する
- 環境変数(local, stg, prod等)を簡単に切り替える
- シナリオで使用するデータをCSVファイルから読み込む
- 開発中に便利なロギングの設定を入れる
- プロジェクト内のコードフォーマットを統一し、自動でチェックする
必要最低限、負荷スクリプトを開発するために必要な事柄は揃っていると思います。
なお、以下は出来ていないです
- テストコード(必要であれば適宜追加をお願いいたします)
- Redisの細かなユーザやパスワード設定。デフォルトのまま使っています
ディレクトリ構成は以下の通りです。
それぞれ、もう少し細かく説明していきます。
個々のシナリオとユースケース毎のシナリオセットを綺麗に管理する
シナリオセットとは、スモークテスト用に実行するシナリオ郡、ロードテスト用に実行するシナリオ郡、等のシナリオのまとまりを指しています。
開発中はVUの数が少ないスモークテストを実行しつつ、本番では大量のVUを用いるロードテスト用のシナリオを実行する。といった使い方が考えられます。
そのため、シナリオとシナリオセットは多対多の関係になることが多いです。
なので、これらのファイルの管理方法は事前に考えておくのがベターです。
そこで、本プロジェクトでは以下のディレクトリ構成としています。
シナリオは/scenariosディレクトリ配下に配置しておき、実際に実行する際には親ファイル(loadTest.ts)を呼び出します。
シナリオセットの管理は、/configsディレクトリ配下で行っています。
シナリオセット毎に、jsonのconfigファイルを準備するイメージです。
jsonのconfigファイルは以下のフォーマットとなっています。
ここで、どのシナリオを、どの程度の負荷で動作させるのか設定します。
あとはk6実行時に、上記のjsonファイルのコマンドラインの引数に渡すだけです。
こうすることで、複数のシナリオを構造的に管理しつつ、実行するシナリオセット(スモークテスト、負荷テスト、etc…)を簡単に切り替えることが出来ます。
環境変数(local, stg, prod等)を簡単に切り替える
負荷試験用のスクリプトを開発する上で、環境の選択は非常に重要です。
エンドポイントを間違ってprodに負荷をかけちゃった…
なんて事態が発生するのも避けたいです。
そこで、このテンプレートプロジェクトでは、「.env」から環境変数を読み込ませるようにしています。
また、不慮の事故が発生しないよう、基本的な環境変数は「env.ts」でexportされた値のみ使用するようにしています。
env.tsでは .env にの環境変数を読み込んで、未設定の環境変数に対してデフォルト値を設定した上で、外部のモジュールから利用可能なようにexportしています。
また、どの環境用のテストデータを利用するのか、テストデータ保管用のディレクトリは環境名で分離させています。
どの環境のテストデータを使うのかも、k6実行時のパラメータとして渡します。
シナリオで使用するデータをCSVファイルから読み込む
負荷試験の準備をしていると、事前にユーザデータを準備して、そのユーザを使って負荷をかけたくなります。
ログインが必要なアプリケーションに対する負荷試験の場合が当てはまります。
基本的には、各シナリオがassets配下にあるcsvファイルを読み込めるようにしています。
また、各シナリオ毎に、各VU(Virtual User)がどこまでのユーザデータを利用済なのかを管理するために、Key/Value storeであるRedisを間に挟めています。
以下はsampleScenario1.tsの抜粋です。
csvファイルからユーザデータは読み込みつつも、csvファイルのインデックス情報はRedisからpopしてくるようにしています。
なぜこのような一手間かけた実装としているのか、その理由については以下の記事を御覧くださいませ。

開発中に便利なロギングの設定を入れる
開発中のみ、デバッグログを流したい。
という話はあるあるだと思います。
本プロジェクトでは、以下のようなfunctionをcommon.ts配下に準備して、その他全てのスクリプトから利用するようにしています。
呼び出す側は以下のようにして呼び出すだけですね。
こうすることで、環境変数側でデバッグログの有無を制御出来ます。
本番の負荷試験中に無意味なログが流れ続けると、それが負荷試験のボトルネックになり得るので、このような仕組みを用意して簡単ロギングの有無を切り替えられるようにすると一安心です。
プロジェクト内のコードフォーマットを統一し、自動でチェックする
これは大したことはしていないので、特に話すことも無いですが…
最低限のCIをgithub actions側に持たせていたり、lintやprettierの設定を入れています。
詳しくはリポジトリを直接ご覧くださいませ。
おわりに
今回は、k6で負荷スクリプトを開発するためのベースとなるプロジェクト構成の例を紹介しました。
この構成にもメリット・デメリットはあると思うので、自分の用途に合うように適宜カスタマイズしてもらえると嬉しいです。
この記事が少しでも皆様のお役に立てれば幸いです。
【追記】 k6側の拡張機能のアップデートも進んでおります。 例えば、本記事執筆後に以下のような修正を加えています。

こちらも併せてご覧くださいませ。