Kubernetes × k6 で負荷試験を実施してみた!
負荷試験はシステムのスケーラビリティを確認する上で重要な工程です!
今回は Kubernetes上で「k6」を利用して負荷試験を行い、その手順をまとめてみました!
1. 環境構築: ローカルk8sを準備
クラスターの準備
まずローカル環境でk8sを動かせるよう、
Kind を利用してクラスタを作成します。
kind create cluster --name kind-control-plane
作成したクラスターを確認
作成されたクラスタを確認しましょう。
kubectl get nodes
こんな感じに出てくるはず・・・!
2. 負荷試験シナリオを JS で記述・ConfigMap登録
JSでシナリオを作成
k6 は JavaScript でテストシナリオを記述します。
まず「test-script.js」とでも名付け、JSファイル作成します。
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function () {
// 作成する環境にHTTPリクエストを送信
let res = http.get('http://podA-service.default.svc.cluster.local:8080');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
configMapのymlを作成
次に、Kubernetes の ConfigMap を作成してシナリオを管理します!
apiVersion: v1
kind: ConfigMap
metadata:
name: k6-script
data:
test-script.js: |
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function () {
let res = http.get('http://podA-service.default.svc.cluster.local:8080');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
適用コマンド!!
kubectl apply -f k6-configmap.yml
3. k6 を実行する Job を作成
Kubernetes の Job を利用して負荷試験を実行する Podを作成します。
k6 を Docker で動作させるため、以下の Job を作成します。
apiVersion: batch/v1
kind: Job
metadata:
name: k6-load-test
spec:
template:
spec:
containers:
- name: k6
image: grafana/k6
args: ["run", "/scripts/test-script.js"]
volumeMounts:
- name: script-volume
mountPath: /scripts
restartPolicy: Never
volumes:
- name: script-volume
configMap:
name: k6-script
適用コマンド:
kubectl apply -f k6-job.yml
4. Job を実行して負荷試験を開始
Job が作成されたことを確認する:
kubectl get pods
ログを確認し、負荷試験の進行状況をチェック:
kubectl logs -f <k6-load-test-pod名>
Jobが起動されると、JSファイルを実行するので
負荷試験が始まっています。
k6の実行結果はこんな感じです↓
execution: local
script: test.js
output: -
scenarios: (100.00%) 1 scenario, 1 max VUs, 1m0s max duration (incl. graceful stop):
* default: 1 looping VUs for 30s (gracefulStop: 30s)
data_received..................: 7.6 MB 248 kB/s
data_sent......................: 17 kB 561 B/s
http_req_blocked...............: avg=15.11ms min=10.9ms med=13.21ms max=66.61ms p(90)=21.56ms p(95)=26.04ms
http_req_connecting............: avg=14.97ms min=10.79ms med=13.09ms max=66.45ms p(90)=21.41ms p(95)=25.9ms
http_req_duration..............: avg=127.24ms min=84.23ms med=94.38ms max=770.35ms p(90)=198.65ms p(95)=349.85ms
{ expected_response:true }...: avg=127.24ms min=84.23ms med=94.38ms max=770.35ms p(90)=198.65ms p(95)=349.85ms
http_req_failed................: 0.00% 0 out of 214
http_req_receiving.............: avg=42.37ms min=11.32ms med=18.32ms max=603.41ms p(90)=74.67ms p(95)=223.57ms
http_req_sending...............: avg=101.75µs min=26µs med=87.5µs max=1.59ms p(90)=120µs p(95)=146µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=84.77ms min=72.53ms med=75.65ms max=190.75ms p(90)=111.3ms p(95)=144.79ms
http_reqs......................: 214 7.013214/s
iteration_duration.............: avg=142.54ms min=95.64ms med=109.7ms max=789.1ms p(90)=218.03ms p(95)=366.01ms
iterations.....................: 214 7.013214/s
vus............................: 1 min=1 max=1
vus_max........................: 1 min=1 max=1
running (0m30.5s), 0/1 VUs, 214 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs 30s
k6のメトリクスを整理しよう
上記結果のサンプルを出してみましたが、それぞれのメトリクスには
こんな意味があります!
メトリクス | 説明 |
---|---|
data_received |
サーバーから受信したデータの合計量 |
data_sent |
クライアントから送信したデータの合計量 |
http_req_blocked |
リクエストがブロックされた時間 |
http_req_connecting |
リクエストが接続を確立するのに要した時間 |
http_req_duration |
リクエストの完了に要した時間(レイテンシ) |
http_req_failed |
リクエストが失敗した割合 |
http_req_receiving |
レスポンスを受信するのに要した時間 |
http_req_sending |
リクエストを送信するのに要した時間 |
http_req_tls_handshaking |
TLSハンドシェイクが行われた時間 |
http_req_waiting |
リクエストがサーバーの応答を待機していた時間 |
http_reqs |
リクエストの総数およびリクエストの実行速度(スループット) |
iteration_duration |
イテレーション(1回のテストサイクル)の完了に要した時間 |
iterations |
イテレーションの総数およびイテレーションの実行速度 |
vus |
同時に実行されている仮想ユーザー数 |
vus_max |
テスト実行中に最大で同時に実行されていた仮想ユーザー数 |
5. CPU やメモリの負荷を確認
負荷試験中に top コマンドを利用して CPU 負荷を確認できます。
kubectl exec -it [pod名] -- top
topコマンドの見方
topコマンドをk8s上で実施すると、これまた色々な情報が
出てきます。
top - 00:56:07 up 27 min, 1 user, load average: 0.01, 0.04, 0.01
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 26.3 us, 0.3 sy, 0.0 ni, 73.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.2 st
MiB Mem : 7810.1 total, 6339.4 free, 795.1 used, 851.3 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 7015.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
831 mysql 20 0 1788052 432308 34944 S 50.7 5.4 1:15.31 mysqld
少し古いですが、topコマンドの解説記事です!
まとめ
いかがでしたでしょうか?
k8sを例に出しましたが、負荷試験を行うことで
- ボトルネックの発見に繋がる
- そもそも何がボトルネックか分かる
- どの程度の負荷がかかってるか分かる
など・・・
業務でも役立つことが多い負荷試験の一例になると思うので
参考になれば幸いです!
後片付け
podとconfigMapを消しておきましょう。
podの削除
kubectl delete pod [pod名]
configMapの削除
kubectl delete cm [ConfigMap名]
ちゃんと削除できてるかな?
# pod情報が何も表示されなければOK
kubectl get pods
# configMapが何も表示されなければOK
kubectl get cm