k6を使った負荷テスト環境をLinodeに10分で構築する

# Linodeとは

Linode (https://www.linode.com/) は Akamaiが提供するIaaS (Infrastructure as a Service) プラットフォームプロバイダーのサービスです。リノードと発音します。
Akamaiは2022年2月にLinode社の買収を発表しました。
https://www.akamai.com/ja/newsroom/press-release/akamai-to-acquire-linode
クラウドコンピューティングをよりシンプルに、手頃な価格で、誰もが利用できるようにすることで、イノベーションを加速することができます。
https://www.linode.com/ja/alternative-cloud-provider/

# k6とは

k6 (https://k6.io/) とは、可視化ツールGrafanaで有名なGrafana Labs社が開発しているオープンソースの負荷テストツールです。JavaScriptを使ってテストシナリオを書くことができ、プロトコルもHTTPだけではなくWebSocketsやgRPCにも対応しています。

# Linodeにk6を使った負荷テスト環境を構築する

この記事では負荷テストツールであるk6に加えて、テストの結果を蓄積する時系列データベースであるInfluxDB、その結果を可視化するGrafanaの3つをLinodeで稼働するLinux仮想マシンにインストールする方法を紹介します。インストールにはLinode独自のデプロイメント自動化機能であるStackScriptsを使うことで、Linodeの予備知識がほぼゼロでも10分以内に負荷テストの実施、可視化までできる環境を構築することができます。

**参考: [Linode StackScriptsとは何か](https://qiita.com/isss802/items/d6e59063d3473659983d)**

まずは以下のリンクから事前に準備しておいたStackScriptを開きます。このStackScriptがk6、InfluxDB、Grafanaを自動的にインストールします。(リンク先にアクセスするにはLinodeのアカウントにログインしておく必要があります)

**StackScripts/grafana-k6**
https://cloud.linode.com/stackscripts/1053069

※もし何らかの理由でこのStackScriptを開くことができなければ、このStackScriptの中身を[GitHubにもアップロードしている](https://raw.githubusercontent.com/hokamoto/stackscripts/main/grafana-k6.sh)のでご使用ください。

「Deploy New Linode」をクリックします
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/5a4851d0-1924-49e8-ef6e-b4e0b33e41ec.png)
StackScriptにはUDF(ユーザー定義フィールド)という、デプロイメントにあたって必要なパラメータを自動的にWebの入力フォームにする機能があります。このStackScriptでは、仮想マシンにSSHログインできる非rootのユーザーのログイン情報や、負荷テストの可視化に使うGrafanaのログイン情報を仮想マシンのデプロイメント時に指定できるようになっています。以下のテキストボックスに必要事項を入力しておきます。
![2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/fd9090d0-e28c-e319-c9cd-3686441e472c.png)
仮想マシンを作成するリージョンと、仮想マシンの種類を選択します。ここでは日本の東京リージョンでDedicated 8 GBのLinodeを選択しています。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/e9bdc2cb-7f75-4fef-5f69-d911815a6bd2.png)
仮想マシンの名前、rootパスワードを指定して「Create Linode」をクリックします
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/2f5fb9fa-a8e1-fde7-862f-983acd3b4d4b.png)
仮想マシンの管理ダッシュボードに画面が遷移するので、仮想マシンの状態がPROVISIONINGからRUNNINGになるまで数分待ちます。同じ画面に今作成した仮想マシンのIPアドレスが表示されているので控えておきます。
![5_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/10de701c-683a-7780-583d-b82f4dff10c8.png)
これで仮想マシンが起動しました。起動した後はStackScriptに沿って必要なソフトウェアのインストールがバックグラウンドで自動的に進みます。

それでは早速仮想マシンにログインしてみます。ログインユーザーは上記「sudoできるユーザーのユーザー名」です。仮想マシンの状態がRUNNINGになった直後はSSHデーモンが起動していないことがあり、SSHでログインできない場合があります。その場合は1,2分待ってからログインを試みてください。このStackScriptはデプロイメントのログを`/var/log/stackscript.log`に出力しているので、内容を確認します。
```console
% ssh hideki@172.104.XX.XX
hideki@172.104.XX.XX's password:

(中略)

$ cat /var/log/stackscript.log

(中略)

          /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: /usr/share/k6/script.js
     output: InfluxDBv1 (http://localhost:8086)

  scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
           * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)


running (00m00.0s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [ 100% ] 1 VUs  00m00.0s/10m0s  1/1 iters, 1 per VU

     data_received........: 0 B 0 B/s
     data_sent............: 0 B 0 B/s
     iteration_duration...: avg=19.03µs min=19.03µs med=19.03µs max=19.03µs p(90)=19.03µs p(95)=19.03µs
     iterations...........: 1   738.264002/s
```
このStackScriptは、デプロイメントの最後にInfluxDBのデータベース作成を兼ねて1回だけダミーの負荷試験を実行します。`stackscript.log`の末尾が上記のようにk6の実行結果になっていれば仮想マシンのセットアップは全て完了して負荷テストができる状態になっています。もし異なる結果が得られた場合はまだセットアップが終わっていないので、定期的に`stackscript.log`の中を確認してください。

**あと一息です! これで負荷テストの準備は完了です!**

最初の負荷テストシナリオを準備します。ここでは[k6のドキュメントにあるサンプル](https://k6.io/docs/getting-started/running-k6/)を使います。vimやnanoなどのテキストエディタで、以下のJavaScriptを`script.js`という名前で保存します。

```javascript
import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('https://test.k6.io');
  sleep(1);
}
```

それでは早速負荷テストをしてみます。ここでは仮想ユーザー数3、テスト時間30秒、テスト結果をローカルのInfluxDBに出力してみます。なお、このあと可視化に使うGrafanaではInfluxDBの`myk6db`というデータベースに負荷テストの結果が出力されているという前提でダッシュボードを生成しているので、動作確認の意味でもまずは`myk6db`に結果を出力することを推奨します。

```console
$ k6 run --vus 3 --duration 30s --out influxdb=http://localhost:8086/myk6db script.js

          /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: script.js
     output: InfluxDBv1 (http://localhost:8086)

  scenarios: (100.00%) 1 scenario, 3 max VUs, 1m0s max duration (incl. graceful stop):
           * default: 3 looping VUs for 30s (gracefulStop: 30s)


running (0m30.9s), 0/3 VUs, 77 complete and 0 interrupted iterations
default ✓ [======================================] 3 VUs  30s

(中略)
```

負荷テストが無事に終わったらGrafanaで結果を見てみます。Webブラウザーから`http://[仮想マシンのIPアドレス]:3000/`にアクセスします。Grafanaのログインユーザーとパスワードは、仮想マシンのデプロイメント時に指定したものを入力します。この際、ログイン直後にパスワードの変更を求められることがあります。
![6_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/38fcaffb-a16e-1ec0-ee38-654a2539e320.png)
必要なダッシュボードはStackScriptがすでに作成しているので、それを開きます。
![7_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/e423dd4e-c0fc-465f-0900-0257846918f1.png)
![8_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/79646c8d-549b-d374-6e24-ebb0326220fb.png)
![9_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19811/309b9a14-f177-c11e-343a-995647269403.png)

**おめでとうございます! これで負荷テスト環境が完成しました!**

慣れると10分程度でここまで来られるので、誰でも簡単に負荷テストを行うことができます。

## 大規模負荷負荷テストに向けて

1台の仮想マシンでかけられる負荷の大きさは、テストシナリオやLinodeのインスタンスタイプに依存します。たとえば、上記で紹介したもっともシンプルな負荷テストシナリオを今回作成したDedicated 8 GBのLinode上で実行すると、8,000仮想ユーザー程度までは比較的安定して増やすことができました。それ以上の仮想ユーザー数になるとInfluxDBに対するテスト結果の保存処理がボトルネックになり、`The flush operation took higher than the expected set push interval.` という警告が多発するので、より高性能なインスタンスタイプを選択して環境を構築する、InfluxDBを別サーバーに分離するなどの対処が必要です。(参考: [The flush operation took higher than the expected set push interval](https://community.k6.io/t/the-flush-operation-took-higher-than-the-expected-set-push-interval/2469/7))

以下のドキュメントでは大規模負荷テストに向けての考慮事項が詳述されていますので、一度確認することをおすすめします。とりわけ「Monitor the load generator server (負荷生成サーバーの監視)」が重要です。なお、このドキュメントに書かれているOSのチューニングについては、デプロイメント時にStackScriptが自動的に実施していますので改めて実施する必要はありません。

**Running large tests**
https://k6.io/docs/testing-guides/running-large-tests/

また、このドキュメントには「Data transfer costs (データ転送コスト)」についての考慮事項も記載されています。Linodeはインバウンド転送が無料、アウトバウンド転送にかかる費用も仮想マシンの価格に含まれているため、負荷テストにかかる総コストが抑えられる可能性があります。たとえば今回使用したDedicated 8 GBのLinodeには5TBまでのアウトバウンド転送費用が含まれています。コストについては「[クラウド見積もりツール](https://www.linode.com/ja/estimator/)」で試算できます。

# 関連記事

アカマイ・テクノロジーズ合同会社のQiitaではLinode関連など開発者向けの記事を記載しております。

https://qiita.com/organizations/Akamai