k6(Grafana k6)は、JavaScriptまたはTypeScriptでシナリオを書き、コマンド1つで負荷テストを実行できるオープンソースのツールです。2026年5月に v2.0.0 が出て古いコマンドがまとめて削除され、2026年9月28日時点の最新安定版は、2026年9月21日公開の v2.3.0 です。この記事では、OS別のインストールから、スクリプトの書き方、合否判定、HTMLレポート、v1からの移行点、k6 StudioとGrafana Cloud k6の料金までを、v2.3.0 を手元で動かした結果に基づいて解説します。
まとめ
- k6はGrafana Labsが開発するGo製の負荷テストツールで、ライセンスはAGPL-3.0。本体は無料で使えます。
- インストールは macOS が
brew install k6、Windows がwinget install k6 --source winget、Debian/Ubuntu は公式APTリポジトリ、Docker はgrafana/k6イメージです。 - 負荷の形は
stagesやscenarios、合否はthresholdsで決めます。閾値を割ると終了コード99で終わるので、CIの失敗判定にそのまま使えます。 - HTMLレポートは
K6_WEB_DASHBOARD_EXPORTで出せますが、既定設定では20秒未満の試験だと出力されません。 - v2では
k6 login・--no-summary・externally-controlledなどが削除されました。v1のスクリプトやCIをそのまま使う前に移行点を確認してください。 - ブラウザ操作の録画からスクリプトを作るならk6 Studio、大規模な負荷をクラウドから掛けるならGrafana Cloud k6(無料枠は月500VUh)を使います。
k6の概要と読み方
k6は「ケー・シックス」と読みます(公式ドキュメントに発音の明記はありません)。もとはLoad Impact社の製品で、2021年にGrafana Labsが買収してからは「Grafana k6」の名前で開発されています。本体はGoで書かれた単一バイナリで、テストシナリオだけをJavaScriptで書きます。TypeScriptは v0.57 から既定で有効になり、.ts ファイルを変換なしで k6 run に渡せます。ただし型情報を取り除くだけで、型チェックはしません。
版の歴史は次のとおりです。v1.0.0 が2025年5月6日、v2.0.0 が2026年5月11日に公開されました。公式のサポート方針では、最新メジャー(v2系)が機能追加の対象で、直前のメジャー(v1系)は重大なバグとセキュリティの修正だけを受けます。実際に2026年8月12日には v1.8.1 がセキュリティ更新として出ています。
JMeter・Gatling・Locustとの違い
| ツール | シナリオの書き方 | 実行環境 | 向いている場面 |
|---|---|---|---|
| k6 | JavaScript/TypeScript | Go製の単一バイナリ | APIの負荷試験をコードで管理しCIで回す |
| JMeter | GUIで組むXML(.jmx) | Java | GUIでシナリオを組む/対応プロトコルの多さ |
| Gatling | Java/Kotlin/Scala/JavaScript/TypeScript | JVM | JVM系のチーム |
| Locust | Python | Python+Web UI | Pythonで書きたいチーム |
k6を選ぶ理由は、シナリオをアプリのコードと同じリポジトリに置き、レビューとCIの流れに乗せられる点です。逆に、k6のJavaScriptはNode.jsではなくGo上の実行環境で動くため、fs や net などNode.js固有のモジュールに依存するnpmパッケージはそのまま読み込めません。社内のテスト資産がPythonならLocust、GUIで組んだJMeterの資産が大量にあるならJMeterを続けるほうが移行コストは小さく済みます。Pythonで書く場合の手順はLocustの使い方と分散実行、ツール全体の比較は負荷テストツールの比較記事にまとめています。
k6のインストール手順:macOS・Windows・Linux・Docker
どのOSでも、インストール後に k6 version を実行して版番号が表示されれば完了です。手元のmacOS(Intel)では k6 v2.3.0 (commit/e088784614, go1.26.8, darwin/amd64) と表示されました。
macOS:Homebrew
brew install k6
k6 version
# 更新
brew upgrade k6
Homebrewの公式Formulaは2026年9月時点で v2.3.0 を配布しています。Homebrewを使わない場合は、GitHub Releasesの k6-v2.3.0-macos-arm64.zip(Apple Silicon)または macos-amd64.zip(Intel)を展開し、中の k6 をPATHの通った場所へ置きます。
Windows:winget・MSI・Chocolatey
winget install k6 --source winget
# 更新
winget upgrade k6
公式ドキュメントが挙げる手段は、winget、MSIインストーラー(https://dl.k6.io/msi/k6-latest-amd64.msi)、Chocolateyの3つです。Chocolateyの choco install k6 は公式ドキュメント上「unofficial(非公式)」のパッケージと明記されているので、社内の標準がChocolateyでない限りwingetかMSIを選んでください。インストール直後に k6 が見つからないと言われたら、ターミナルを開き直してPATHを読み込み直します。
Linux:Debian・Ubuntu・Fedora
# Debian / Ubuntu
curl -fsSL https://dl.k6.io/key.gpg | 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 k6
# Fedora / CentOS
sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6
apt install k6 の前に、上の手順で公式リポジトリを登録しておく必要があります。最小構成のイメージで gpg が失敗する場合は ca-certificates と gnupg2 を先に入れます。Amazon Linux 2やCentOS 7以前はPGP V4署名に対応していないため、公式の障害対応ページは yum install --nogpgcheck k6 を案内しています。
Docker:ホストへのk6インストールが不要な実行方法
docker pull grafana/k6
# スクリプトは標準入力で渡す
docker run --rm -i grafana/k6 run - <script.js
# ブラウザテスト用(Chromium同梱)
docker pull grafana/k6:master-with-browser
コンテナの中からはホストのファイルが見えないので、k6 run script.js とファイル名だけを渡しても動きません。上のように - を指定して標準入力で流すか、-v $PWD:/app -w /app でディレクトリをマウントします。スクリプトから open() でCSVを読む場合はマウントが必要です。
最初のテストスクリプト:k6 newからk6 runまで
k6 new を実行すると、10VUで30秒間 https://quickpizza.grafana.com へアクセスする雛形 script.js ができます。雛形の宛先はGrafanaが用意した練習用サイトなので、自社のシステムを試すときは必ず書き換えてください。以下の例は、GET /health に200を返す検証用サーバー(既定は localhost:8080)を前提にしています。宛先は環境変数 BASE_URL で変えられます。以下は、5秒で1→10VUへ増やし、10秒間維持して、5秒で0VUへ減らす試験です。
import http from 'k6/http';
import { check, sleep } from 'k6';
const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
export const options = {
stages: [
{ duration: '5s', target: 10 },
{ duration: '10s', target: 10 },
{ duration: '5s', target: 0 },
],
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500'],
},
};
export default function () {
const res = http.get(BASE_URL + '/health');
check(res, {
'status is 200': (r) => r.status === 200,
});
sleep(1);
}
default 関数が1回の反復(iteration)で、各VUがこれを繰り返します。sleep(1) は利用者の待ち時間の代わりです。外すと各VUは応答を受け取り次第、次の反復へ進むため、リクエスト数はVU数と応答時間に左右されます。k6 run script.js で実行すると、手元の検証サーバーでは次の結果になりました(抜粋)。
█ THRESHOLDS
http_req_duration
✓ 'p(95)<500' p(95)=95.94ms
http_req_failed
✓ 'rate<0.01' rate=0.00%
█ TOTAL RESULTS
checks_succeeded...: 100.00% 145 out of 145
http_req_duration..............: avg=86.21ms min=25.09ms med=93.03ms max=96.41ms p(90)=95.75ms p(95)=95.94ms
http_req_failed................: 0.00% 0 out of 145
http_reqs......................: 145 7.006027/s
vus............................: 2 min=2 max=10
| 項目 | 意味 |
|---|---|
| http_req_duration | リクエストの応答時間。p(95)は95パーセンタイル |
| http_req_failed | 失敗したリクエストの割合(既定では4xx・5xxも失敗) |
| http_reqs | 総リクエスト数と1秒あたりの件数 |
| checks_succeeded | check()の成功率。失敗しても試験は止まらない |
| vus | 同時に動いていた仮想ユーザー数 |
平均値(avg)だけを見ると、一部の遅い応答が埋もれます。判定には p(95) や p(99) を使ってください。表示するパーセンタイルは --summary-trend-stats "avg,p(95),p(99)" で変えられます。
負荷のかけ方を決めるオプション:vus・duration・stages・scenarios
一定の負荷を短く掛けるだけなら、コマンドラインで足ります。
k6 run --vus 10 --duration 30s script.js
k6 run --once script.js # v2.3.0で追加:1VU・1反復だけ実行(スモークテスト用)
同じ設定をスクリプト・環境変数・コマンドラインの複数箇所に書いた場合、優先順位は「既定値 < --config の設定ファイル < スクリプトの options < K6_ で始まる環境変数 < コマンドラインのフラグ」です。手元でも、スクリプトに vus: 2 と書いて K6_VUS=4 を付けると4VUで動き、さらに -u 6 を足すと6VUになりました。CIで一時的に負荷を変えたいときは、スクリプトを書き換えずにフラグで上書きできます。
stagesとscenariosの使い分け
stages はVU数を段階的に増減させる書き方で、上の例のように徐々に負荷を上げる試験に使います。一方、毎秒50回の反復を開始したい場合は、VU数ではなく反復の開始間隔を制御する scenarios の constant-arrival-rate を使います。VUベースの試験では、サーバーが遅くなるほど1VUあたりの反復数が減り、負荷が勝手に下がってしまうためです。到着率ベースでは、用意したVU(maxVUs)が足りなくなると予定した反復を開始できず、dropped_iterations として数えられます。
export const options = {
scenarios: {
browse: {
executor: 'constant-arrival-rate',
rate: 50,
timeUnit: '1s',
duration: '1m',
preAllocatedVUs: 20,
maxVUs: 100,
exec: 'browse',
},
checkout: {
executor: 'ramping-vus',
stages: [
{ duration: '30s', target: 5 },
{ duration: '30s', target: 0 },
],
exec: 'checkout',
},
},
};
export function browse() {
http.get(BASE_URL + '/health');
}
export function checkout() {
http.get(BASE_URL + '/health');
sleep(1);
}
最初のスクリプトの options をこれに置き換え、exec で指定した名前の関数を書き足して使います(インポートと BASE_URL はそのまま残します)。
v2.3.0 からは k6 run --scenario browse script.js のように、名前を指定して一部のシナリオだけを実行できます。複数ならカンマ区切りです。ただし --vus や --duration との併用はできず、--scenario cannot be combined with --duration というエラーで止まります。1反復でHTTPリクエストを1件だけ送る(リダイレクトなし)条件で browse だけを手元で実行すると、1分間で3,001リクエスト(49.95件/秒)となり、指定した毎秒50回に揃いました。1反復で複数のリクエストを送れば、リクエスト数はその倍数になります。
thresholdsとcheckによる合否判定
check() は結果を数えるだけで、失敗しても試験は続き、終了コードにも影響しません。試験の合否を決めるのは thresholds です。閾値を割ると、k6は最後まで走ったうえで終了コード99を返します。途中で打ち切りたい場合は長形式で abortOnFail を付けます。次の例は、最初のスクリプトの options だけを置き換えて使います。
export const options = {
vus: 5,
duration: '20s',
thresholds: {
http_req_failed: [
{ threshold: 'rate<0.05', abortOnFail: true, delayAbortEval: '5s' },
],
},
};
約25%が500エラーを返す検証サーバーに当てたところ、開始から6秒で thresholds on metrics 'http_req_failed' were crossed; at least one has abortOnFail enabled, stopping test prematurely と出て止まり、終了コードは99でした。delayAbortEval は開始直後の数件の失敗で即中止にならないよう、判定を遅らせる設定です。
スクリプトから試験を止める関数は2つあり、挙動がまったく違います。
| 書き方 | 止まる範囲 | 終了コード |
|---|---|---|
fail('理由') |
その反復だけ。次の反復は実行される | 変わらない |
exec.test.abort('理由') |
試験全体 | 108 |
exec.test.fail('理由') |
止まらない(失敗の印だけ付く) | 110 |
thresholds 違反 |
最後まで実行(abortOnFailなら途中で) | 99 |
| クラウド実行が閾値以外で中断 | 試験全体 | 97(v2.0.0から) |
fail() で試験全体が止まると誤解されがちですが、手元の確認では反復0で fail() を呼んでも反復1は通常どおり動きました。CIで「致命的なエラーなら即失敗にしたい」場面では k6/execution の exec.test.abort() を使ってください。なお v2.0.0 より前は、クラウド実行がユーザー操作やタイムアウトで中断しても終了コードが0だったため、v1時代のCIは失敗を見逃している可能性があります。
環境変数の渡し方:__ENVと-e、.envファイル
スクリプトの中では、環境変数をグローバルオブジェクト __ENV で読みます。値は -e(--env)で渡します。
k6 run -e BASE_URL=https://staging.example.com script.js
BASE_URL=https://staging.example.com k6 run script.js
2行目のようにシェルの環境変数として渡しても読めます(Bash・zshの書式です。WindowsのPowerShellでは $env:BASE_URL='https://staging.example.com'; k6 run script.js とします)。k6 run によるローカル実行では、既定でシステムの環境変数を __ENV に取り込むためで、--include-system-env-vars=false を付けると -e で渡した値しか見えなくなります。CIのシークレットが意図せずスクリプトから見えるのを避けたいときに使います。
注意点が2つあります。まず、-e VUS=10 のように渡してもk6の実行オプションは変わりません。オプションを環境変数で変えるなら K6_VUS=10 のように K6_ 接頭辞を付けます。次に、k6 run には .env ファイルを読み込むフラグがありません(v2.3.0の --help で確認)。.env を使う場合は、シェル側で set -a; . ./.env; set +a と読み込んでから実行するか、Dockerなら docker run --env-file .env で渡します。
実践例:ログイン付きAPIとCSVのテストデータ
ログインしてトークンを取り、その後のAPI呼び出しに付ける構成です。スクリプトと同じディレクトリに、1行目が name,password の users.csv を置きます(値にカンマや改行を含まない前提の簡易な読み込みです)。TypeScriptで書いた例ですが、.js にして型注釈を消せばJavaScriptでも同じです。
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
import exec from 'k6/execution';
const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
// init段階で1回だけ読み、全VUで共有する
const users = new SharedArray('users', () =>
open('./users.csv').trim().split('\n').slice(1).map((line) => {
const [name, password] = line.split(',');
return { name, password };
})
);
export const options = { vus: 2, iterations: 6 };
export function setup(): { token: string } {
const res = http.post(BASE_URL + '/login', JSON.stringify({ user: 'admin' }), {
headers: { 'Content-Type': 'application/json' },
});
return { token: res.json('token') as string };
}
export default function (data: { token: string }) {
const user = users[exec.scenario.iterationInTest % users.length];
const res = http.post(BASE_URL + '/api/orders', JSON.stringify({ user: user.name }), {
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + data.token,
},
});
check(res, { 'status is 200': (r) => r.status === 200 });
}
setup() は試験の最初に1回だけ実行され、戻り値が各VUの default 関数の引数に渡されます。反復ごとにログインさせる場合は、default の中でログインします。各VUで最初の1回だけログインする場合は、VUごとの変数にトークンを保持し、未取得の場合だけログイン処理を実行します。CSVを SharedArray に入れるのは、普通の配列だとVUの数だけデータが複製され、数千行のCSVではメモリを大きく消費するためです。exec.scenario.iterationInTest はシナリオ内で一意の反復番号です。この例は行数で剰余を取るため、末尾まで使うと先頭行へ戻り、同じ行を再利用します。複数VUでの実行順や完了順は保証されません。手元の確認では、4反復で alice・bob・carol・alice の順に割り当てられました。
結果の出力とHTMLレポート:web dashboardが出ない原因
web dashboardは、拡張機能(xk6-dashboard)を基にv0.49.0で本体へ組み込まれ、v2でも利用できます。環境変数で有効にすると、試験中は http://127.0.0.1:5665 でグラフを見られ、終了時にHTMLレポートを保存できます。
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=report.html k6 run script.js
# 短い試験でレポートを出す場合は集計周期を縮める
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_PERIOD=1s K6_WEB_DASHBOARD_EXPORT=report.html k6 run script.js
ここで多いのが「report.html が作られない」というつまずきです。手元で試験時間を変えて確かめると、既定設定では19秒の試験で The test run was short, report generation was skipped (not enough data) と警告が出てファイルが作られず、21秒の試験では作られました。ソースコード(internal/dashboard/report.go)では、既定10秒ごとに取る集計が1回以下だとレポートを作りません。スモークテストのような短い試験でレポートが欲しい場合は、2行目のように K6_WEB_DASHBOARD_PERIOD=1s を付けると5秒の試験でも出力されました。web dashboardの公式ドキュメントでは、グラフが描かれるのは試験時間が集計周期の3倍を超える場合とされています。
ダッシュボード以外の出力先は用途で選びます。
- 終了時のサマリーをJSONで残す:
--summary-export=summary.json、またはhandleSummary()関数で任意の形式に書き出す - 各メトリクスの時系列データを残す:
--out json=results.jsonや--out csv=results.csv(CSVはメトリクス名・タイムスタンプ・値・URL・ステータスなどの列) - Grafanaで時系列を見る:
-o experimental-prometheus-rw(Prometheus)や-o opentelemetry、InfluxDBへの出力
Grafanaと組み合わせる場合は、Prometheusに送ってGrafanaのダッシュボードで試験中の変化を見るのが一般的な構成です。試験後にチームで共有するだけなら、HTMLレポート1ファイルで足ります。
k6 v2の破壊的変更:v1のスクリプトとCIの移行点
v2.0.0 では、v1時代に非推奨になっていたコマンドや設定がまとめて削除されました。v1向けの記事やスクリプトをそのまま使うとエラーになる箇所です(全項目はv2.0.0のリリースノートにあります)。
| v1までの書き方 | v2での扱い |
|---|---|
k6 login cloud |
k6 cloud login に変更 |
k6 cloud script.js |
k6 cloud run script.js に変更 |
--no-summary |
--summary-mode=disabled に変更 |
--summary-mode=legacy |
削除(compact か full を選ぶ) |
--upload-only |
k6 cloud upload に変更 |
k6 pause/resume/scale/status |
削除(代替なし) |
executor: externally-controlled |
削除。スクリプトが起動しない |
options.ext.loadimpact |
options.cloud に移す |
k6/experimental/redis |
k6/x/redis(拡張を自動取得) |
REST API(localhost:6565) |
--address 指定時だけ起動 |
影響が大きいのはGrafana Cloud k6を使っているチームです。v2では k6 cloud 系のコマンドすべてでスタック(Grafana Cloudの環境)の指定が必須になり、最初のスタックを自動で選ぶ動作がなくなりました。k6 cloud login をやり直すか、環境変数 K6_CLOUD_STACK_ID を設定してください。拡張機能を自作している場合は、Goのモジュールパスが go.k6.io/k6 から go.k6.io/k6/v2 に変わっています。
k6 StudioとGrafana Cloud k6:無料枠と料金
k6 Studio:ブラウザ操作の録画からスクリプトを作るデスクトップアプリ
k6 Studioは、ブラウザでの操作を録画してHARファイルを作り、そこからk6のスクリプトを生成するデスクトップアプリです。k6本体はGUIを持たないので、「k6のGUI」を探している場合はこちらが該当します。Windows・macOS・Linuxに対応し、録画にはGoogle Chromeが必要です(Linux ARM64はChromiumで代用可)。ライセンスはk6本体と同じAGPL-3.0で無料です。GitHub上の最新は v2.1.0(2026年8月11日)です。
Grafana Cloud k6:無料枠と課金の数え方
| プラン | 料金 | 含まれる量 |
|---|---|---|
| Free | 0ドル | 月500VUhまで |
| Pro | 月19ドルのプラットフォーム料+従量 | 月500VUh込み、超過は0.150ドル/VUh〜 |
| Enterprise | 個別見積もり | 年間契約 |
VUh(仮想ユーザー時間)の基本式は「最大VU数×実行時間(分)÷60」です。ただし constant-arrival-rate などの到着率ベースのシナリオでは、実際に動いたVU数ではなく設定した maxVUs(未設定なら preAllocatedVUs)で計算されるため、maxVUs を大きめに取ると請求も増えます。100VUで10分の試験なら約17VUhなので、無料枠の500VUhではこの規模の試験を月に約30回回せます。ブラウザを使うVUは10倍で数えられ、手元のk6で実行して結果だけをクラウドへ送る場合(k6 cloud run --local-execution)は、Fractional VUH v2の契約ではVUh計算に25%の割引調整が適用されます。旧計算モデルではこの調整は適用されません。料金は改定されることがあるため、契約前にGrafana Cloudの料金ページで最新の表を確認してください。
k6 cloud login -t <トークン> --stack <スタックのURLまたはslug>
k6 cloud run script.js # Grafanaの負荷生成サーバーから実行
k6 cloud run --local-execution script.js # 手元で実行し結果だけ送る
CI/CDへの組み込み:GitHub Actionsの公式アクション
GitHub Actionsでは、Grafana公式の grafana/setup-k6-action でk6を入れ、grafana/run-k6-action でスクリプトを実行します。閾値を割れば終了コード99でジョブが失敗するので、判定のための追加スクリプトは要りません。
name: load-test
on:
pull_request:
jobs:
k6:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: grafana/setup-k6-action@v1
with:
k6-version: '2.3.0'
- uses: grafana/run-k6-action@v1
env:
BASE_URL: ${{ vars.STAGING_URL }}
with:
path: ./tests/*.js
flags: --summary-mode=full
k6-version を省くとその時点の版が入り、メジャー更新の日にCIが突然壊れることがあります。v1から v2 への移行で実際に起きた変化なので、版は固定しておくのが安全です。Grafana Cloud k6へ結果を送る場合は K6_CLOUD_TOKEN と K6_CLOUD_PROJECT_ID に加えて、v2では K6_CLOUD_STACK_ID も必要です(run-k6-action のREADMEの例にはこの変数が無く、注記で補われています)。性能目標をどう数値にして閾値へ落とすかは、非機能要件の数値化とk6での閾値テストで扱っています。
よくある質問
k6の読み方は?
「ケー・シックス」と読みます。公式ドキュメントに発音の明記はありませんが、製品名の綴りどおりの読み方です。
k6は無料で使えますか?
k6本体とk6 StudioはAGPL-3.0のオープンソースで、無料で使えます。料金がかかるのはGrafanaのクラウドから負荷を掛けるGrafana Cloud k6で、こちらも月500VUhまでは無料プランで使えます。
Windowsにk6をインストールするには?
winget install k6 --source winget を実行するか、公式のMSIインストーラーを使います。Chocolateyのパッケージもありますが、公式ドキュメントでは非公式の扱いです。
k6でHTMLレポートを出力するには?
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=report.html k6 run script.js で出力できます。既定設定では20秒未満の試験だとレポートが作られないため、短い試験では K6_WEB_DASHBOARD_PERIOD=1s を併用します。
k6とk6 Studioの違いは?
k6はスクリプトを実行するコマンドラインツール、k6 Studioはブラウザ操作の録画からk6のスクリプトを作るデスクトップアプリです。k6 Studioで作ったスクリプトも、実行するのはk6本体です。