「自分のVPSやアプリ、実際どれくらいのアクセスに耐えられるんだろう?」——そんな疑問に答えてくれるのが負荷テストツールの k6 です。結論から言うと、Docker さえ入っていれば1行のコマンドで起動でき、テストシナリオは JavaScript で書けるので、コードが書ける人なら30分でファーストテストを動かせます。
この記事では、実際に grafana/k6(v2.0.0)を Docker で動かし、ローカルの nginx:alpine に対して40秒の負荷テストを実行した実測データをすべて載せています。インストールで詰まりやすいポイント(特に arm64 環境)も、実際に手を動かして確認した結果をそのまま共有します。
この記事のポイント
grafana/k6:latest(v2.0.0)は Docker イメージ1行で即起動できる(イメージサイズ実測 67.6MB)- テストスクリプトは JavaScript(ES2015+)で書き、VU数・ステージ・閾値を宣言的に設定する
- 実測では最大10VU・40秒で440リクエスト全成功・p(95)=0.92ms・エラー率0%・checks 880件100%を確認
thresholdsを設定すると「基準を超えたらCIで失敗させる」仕組みが簡単に作れる- 注意:apt 公式リポジトリ(dl.k6.io)は amd64 / i386 のみ。arm64(Apple Silicon等)では
apt install k6が失敗するので Docker を使う
動作確認済み環境
本記事のコマンドは次の環境で実際に実行・確認しています。
- k6:
grafana/k6:latest(k6 v2.0.0+dirty (commit/8c3be52cc1-dirty, go1.26.3, linux/arm64)) - ホスト:macOS / Docker 20.10.12(Apple Silicon・arm64)
- テストターゲット:
nginx:alpine(実バージョンnginx/1.31.1、Docker内部ネットワークk6lab_net) - 計測日:2026-06-14
k6 とは何か — 他のツールとの違い
k6 は Grafana Labs が開発するオープンソースの負荷テストツールです。JMeter・Locust・ab(Apache Bench)などと並ぶ選択肢ですが、テストスクリプトを JavaScript(ES2015+)で書く点が最大の特徴です。
従来の JMeter は XML のシナリオ定義で設定が煩雑になりがちでした。k6 では、普段フロントエンドやサーバーサイドで使う感覚と同じ JavaScript でシナリオを書けるため、コードレビュー・Git管理・CI連携との相性が抜群です。エンジンは Go 製のシングルバイナリ(今回の実測では go1.26.3)なので動作も軽量です。
| ツール | スクリプト言語 | インストール | GUI | CI連携 | 特徴 |
|---|---|---|---|---|---|
| k6 | JavaScript | Docker 1行 / apt | オプション(Web Dashboard) | ◎ 終了コードで判定 | シンプル・開発者向け |
| JMeter | XML(GUI操作) | Java必須 | あり(重い) | ○ プラグイン必要 | 機能豊富・設定複雑 |
| Locust | Python | pip install | あり(軽量) | ○ CLIモードあり | Python使いに親しみやすい |
| ab(Apache Bench) | CLIオプション | apt install apache2-utils | なし | △ 出力パース必要 | シンプル・単機能 |
インストール方法:Docker vs apt
k6 を使うには主に2つの方法があります。先に結論を言うと、特に arm64 環境(Apple Silicon の Mac や ARM系VPS)では Docker 一択です。理由は後述しますが、まず両方の方法を見ていきましょう。
①Docker で使う(おすすめ・環境を汚さない)
最もお手軽な方法です。Docker さえ入っていれば、apt でのパッケージ管理不要で k6 がすぐ使えます。バージョン確認だけで実際に動くことが分かります。
k6 v2.0.0+dirty (commit/8c3be52cc1-dirty, go1.26.3, linux/arm64)
これだけです。今回実測した grafana/k6:latest のイメージサイズは 67.6MB と軽量で、起動も一瞬でした(2026-06-14 時点で v2.0.0 が最新)。Docker イメージはマルチアーキ対応なので、arm64 でも amd64 でもそのまま同じコマンドで動きます。
②apt でインストールする(amd64 のVPS・常用環境向け)
Ubuntu の VPS に k6 を常駐させたい場合は、公式 apt リポジトリ(dl.k6.io)からインストールします。GPG鍵を登録してからリポジトリを追加する流れです。
# k6 リポジトリの署名鍵(C780D0BDB1A69C86)を登録
$ curl -fsSL “https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xC780D0BDB1A69C86” \
| sudo gpg –dearmor -o /usr/share/keyrings/k6-archive-keyring.gpg
$ echo “deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] \
https://dl.k6.io/deb stable main” | sudo tee /etc/apt/sources.list.d/k6.list
$ sudo apt-get update && sudo apt-get install -y k6
Get:1 https://dl.k6.io/deb stable/main amd64 k6 amd64 2.0.0 [27.9 MB]
Setting up k6 (2.0.0) …
$ k6 version
k6 v2.0.0 (commit/8c3be52cc1, go1.26.3, linux/amd64)
amd64 環境では上記の通り k6 amd64 2.0.0(.deb は約27.9MB)が問題なくインストールできました。

注意:arm64 では apt が失敗します(実測でハマったポイント)
正直、ここはかなり詰まりました。実際に Apple Silicon(arm64)の環境で apt インストールを試したところ、apt-get install k6 が E: Unable to locate package k6 で失敗します。調べると、公式リポジトリ dl.k6.io の InRelease は Architectures: amd64 i386 のみで、binary-arm64/Packages は HTTP 404(arm64向けの .deb が存在しない)でした。ARM系VPS(Oracle Ampere、AWS Graviton など)や Apple Silicon では、apt ではなく Docker(マルチアーキ対応)か xk6 でのビルドを使ってください。
最初のテストスクリプトを書く
k6 のテストスクリプトは JavaScript ファイルです。最小構成を見てみましょう。
import http from ‘k6/http’;
import { sleep } from ‘k6’;
export const options = {
vus: 10, // 仮想ユーザー数(同時接続数)
duration: ’30s’, // テスト時間
};
export default function () {
http.get(‘https://example.com/’);
sleep(1);
}
ポイントは3つです。
options:VU数・実行時間などのシナリオ設定をまとめて書くexport default function:各VUが繰り返し実行するリクエスト処理sleep(1):1VUが1秒待ってから次のリクエストを送る(実際のユーザー動作に近づける)
実行は次のコマンドです。Docker の場合はスクリプトをコンテナにマウントして渡します。
$ docker run –rm -v $(pwd)/test.js:/work/test.js grafana/k6 run /work/test.js
# apt インストール済み(amd64)の場合
$ k6 run test.js
ステージとthresholdsで本格シナリオを書く
実際の負荷テストでは「徐々にユーザーを増やして最大負荷に到達させる」ステージ設計(ramping VU)が重要です。また閾値(thresholds)を設定することで、基準を超えたら CI で自動的に失敗させる仕組みが作れます。今回実測に使った loadtest.js がこちらです。
import { check, sleep } from ‘k6’;
export const options = {
stages: [
{ duration: ’10s’, target: 5 }, // 0→5VU にランプアップ
{ duration: ’20s’, target: 10 }, // 10VU で定常負荷
{ duration: ’10s’, target: 0 }, // 0VU にランプダウン
],
thresholds: {
http_req_duration: [‘p(95)<500’], // 95%タイルが500ms未満
http_req_failed: [‘rate<0.01’], // エラー率1%未満
checks: [‘rate>0.99’], // checks成功率99%超
},
};
export default function () {
const res = http.get(‘http://k6lab_nginx/’);
check(res, {
‘status is 200’: (r) => r.status === 200,
‘response time < 500ms’: (r) => r.timings.duration < 500,
});
sleep(0.5);
}
このスクリプトを、同じ Docker ネットワーク(k6lab_net)内に立てた nginx:alpine(nginx/1.31.1)に対して実際に実行しました。
実測結果:k6 負荷テストを実際に動かしてみた
上記のステージ設定(0→5→10→0VU、計40秒)で実行した結果がこちらです。テスト終了後に k6 が出力したエンドサマリーをそのまま図にしました。

主要な結果をまとめると次の通りです。
- 総リクエスト数:440件(40.1秒間)
- スループット:10.97 req/s
- 平均レスポンス時間:0.52ms(med 0.42ms)
- p(95) レスポンス時間:0.92ms(閾値500ms 以内 → PASS)
- エラー率:0.00%(閾値1%未満 → PASS)
- checks 成功率:100%(880件中880件成功、閾値99%超 → PASS)
- 受信データ量:499kB / iteration_duration 平均 501.45ms

レスポンス時間のパーセンタイル分布も見ておきましょう。同一Dockerネットワーク内(ループバックに近い環境)での計測なのでネットワーク遅延は極小ですが、それでも最大値が 10.74ms になっています。これは GC やランタイムの一時的なスパイクで、p(95) でも 0.92ms と、定常状態ではほぼ1ms以下という非常に安定した結果でした。

Web Dashboard でグラフ表示する
k6 には組み込みの Web Dashboard があり、K6_WEB_DASHBOARD=true を付けて実行するとブラウザ(http://127.0.0.1:5665)でリアルタイムにメトリクスを確認できます。さらに K6_WEB_DASHBOARD_EXPORT を指定すると、テスト終了後に自己完結のHTMLレポートが書き出されます。
-e K6_WEB_DASHBOARD=true \
-e K6_WEB_DASHBOARD_EXPORT=/report/k6-report.html \
-v $(pwd)/loadtest.js:/work/loadtest.js \
-v $(pwd)/report:/report grafana/k6 run /work/loadtest.js
web dashboard: http://127.0.0.1:5665
実際に書き出されたレポートのトップ画面がこちらです。VU数の推移・スループット・レスポンス時間が時系列グラフで可視化されます。

Summary タブには全メトリクスの集計テーブルが並びます。http_req_duration の avg/p90/p95/p99 などが一覧で確認できるので、CLI 出力より見やすい場面も多いです。

checks と thresholds の使い方
①check(アサーション)
check はリクエストごとの検証です。戻り値が false になっても k6 は停止せず、チェック成功率として集計されます。今回の実測では880件すべて成功(100%)でした。
‘status is 200’ : (r) => r.status === 200,
‘body contains hello’ : (r) => r.body.includes(‘hello’),
‘response < 500ms’ : (r) => r.timings.duration < 500,
});
②thresholds(合否判定)
thresholds はテスト全体の合否ラインです。条件を満たせなかった場合、k6 は終了コード1で終了するため、CI(GitHub Actions等)で自動的に失敗と判定させられます。今回の実測では3つの閾値すべてが PASS し、終了コードは0でした。
// p(95) が 500ms 未満でなければ FAIL
http_req_duration: [‘p(95)<500’],
// エラー率が 1% 以上なら FAIL
http_req_failed: [‘rate<0.01’],
// checks の成功率が 99% 以上でなければ FAIL
checks: [‘rate>0.99’],
},
主要メトリクスの読み方
k6 の出力で見るべき主要なメトリクスを、今回の実測値と合わせて解説します。
| メトリクス名 | 意味 | 今回の実測値 |
|---|---|---|
http_req_duration |
リクエスト1件あたりのレスポンス時間 | avg 0.52ms / p(95) 0.92ms / max 10.74ms |
http_req_failed |
HTTPエラー(4xx/5xx)の割合 | 0.00%(440件中0件失敗) |
http_reqs |
総リクエスト数と毎秒スループット | 440件 / 10.97 req/s |
checks |
check() アサーションの成功率 | 100%(880件成功) |
vus / vus_max |
現在の仮想ユーザー数 / 最大VU数 | max 10(設定通りに推移) |
iteration_duration |
1イテレーション(リクエスト+sleep)の合計時間 | avg 501.45ms(sleep 0.5s込み) |
よくあるエラーと解決策
①Unable to locate package k6 — arm64でaptが失敗する
前述の通り、公式 apt リポジトリ(dl.k6.io)は amd64 / i386 のみ提供で、arm64 向けのパッケージがありません。Apple Silicon や ARM系VPS では Docker(grafana/k6 はマルチアーキ)を使うのが確実です。リポジトリ追加自体は成功するのに install で初めて気づくので、地味にハマりやすいポイントです。
②ECONNREFUSED — ターゲットに接続できない
url=http://localhost:8080/
Dockerコンテナ内から localhost でホストのサービスを叩こうとすると発生します。コンテナ内の localhost はコンテナ自身を指すためです。解決策は2つあります。
localhostをhost.docker.internalに変更する(Docker Desktop の場合)- テスト対象も同じ Docker ネットワーク上に立てて、コンテナ名で接続する(今回は
--network k6lab_netでつなぎhttp://k6lab_nginx/でアクセスしました)
③閾値 FAIL — p(95) が基準を超えた
✗ ‘p(95)<500’ p(95)=1234.56ms
p(95) が閾値を超えている場合、サーバー側がボトルネックになっています。VU数を下げる・ターゲットのリソースを増やす・アプリのクエリを最適化するなどの対処が必要です。終了コードが1になるので、CIではここでパイプラインが止まります。
GitHub Actions との連携(CI自動化)
k6 のもっとも便利な使い方の一つが CI への組み込みです。thresholds を設定しておけば、テスト失敗時に自動でパイプラインが止まります。
on: [push]
jobs:
k6_load_test:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– name: Run k6 load test
uses: grafana/k6-action@v0.3.1
with:
filename: tests/load.js
公式の grafana/k6-action を使えば設定が最小限で済みます。ubuntu-latest ランナーは amd64 なので、ここでは apt/公式バイナリ経由でも問題なく動きます。thresholds が FAIL した場合は終了コード1が返り、GitHub Actions のステップが failure になります。
実行環境の CPU 性能(sysbench ベンチ)
今回の実測に使用した Docker ホスト環境の CPU 性能も参考に掲載します。sysbench(1.0.20)を ubuntu:24.04 コンテナで3回実行した結果です。

3回の平均は 4,019.80 events/sec(最小 3,315.67 / 最大 4,831.00、2スレッド・各10秒)でした。k6 は Go 製のシングルバイナリで CPU 負荷が軽く、10VU 程度であればローエンドのVPSでも十分動作します。実際、今回の負荷テスト中も k6 側がボトルネックになることはありませんでした。
VPSでk6を使う場合のおすすめ構成
自分のVPSサーバーに対して k6 で負荷テストをかけたい場合、一般的な構成は次の通りです。
| 用途 | k6 実行場所 | テスト対象 | 注意点 |
|---|---|---|---|
| ローカル開発テスト | 手元のPC(Docker) | localhost のサービス | ネットワーク遅延がほぼゼロ |
| 本番VPSの負荷テスト | 別のVPS or ローカル | 本番VPSのIP/ドメイン | テスト元が攻撃者に見える場合あり。VPS契約約款を確認 |
| 本格的な分散負荷テスト | Grafana Cloud k6 | 本番VPS | 複数リージョンから負荷をかけられる。無料枠あり |
注意:VPS に対して過負荷テストをする際の注意
他社VPSに向けて大量のリクエストを送信することは、利用規約違反になる場合があります。自分の管理下にあるサーバーに対してのみ負荷テストを実施してください。また、本番環境への負荷テストは必ずメンテナンスウィンドウや低トラフィック時間帯に行うことをおすすめします。
VPSを借りてサーバーの負荷テストをやってみたい方には、東京リージョンがあって月$5〜の Vultr がコスパ良くておすすめです。ARM(Ampere)プランもありますが、その場合は前述の通り k6 を Docker で動かすのを忘れずに。
まとめ
k6 は JavaScript でテストシナリオを書ける、開発者フレンドリーな負荷テストツールです。今回の実測では次のことを確認しました。
grafana/k6:latest(v2.0.0)は Docker 1行で即起動できる(イメージ実測 67.6MB、2026-06-14 確認)- ステージ設計(ramping VU)でランプアップ→定常→ランプダウンの本格シナリオが書ける
- 実測:最大10VU・40秒で440リクエスト全成功・p(95)=0.92ms・エラー率0%・checks 880件100%
- thresholds を設定することで GitHub Actions などのCIに自動的に組み込める(3閾値すべてPASSで終了コード0)
- apt リポジトリ(dl.k6.io)は amd64/i386 のみ。arm64 環境では Docker を使う
負荷テストは「本番前に一度だけやる」ものではなく、コードの変更のたびに CI で回す仕組みにすることで、レスポンスタイムの劣化を早期に検知できます。まずは Docker でサクッと試してみてください。
より本格的なサーバー構築・VPS運用に興味が出てきたら、 もあわせてどうぞ。


コメント