🌱
EKSで始めるk6 Operatorの導入とサンプルテストの分散実行
前準備:
- iamユーザーの作成
-
aws configure
でcredentialを設定
1. EKSクラスターの作成(Terraform)
このModuleを使用する
• Terraform module to create AWS Elastic Kubernetes (EKS) resources
main.tf
# Local Values
locals {
project = "eks-k6-operator"
region = "ap-northeast-1"
profile = # FIXME: Set your AWS profile
account_id = # FIXME: Set your AWS account ID
cidrs = # FIXME: Set your CIDERS
}
# VPC
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${local.project}-vpc"
cidr = "10.0.0.0/16"
azs = ["${local.region}a", "${local.region}c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
}
# EKS
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "${local.project}-eks"
cluster_version = "1.30"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
control_plane_subnet_ids = module.vpc.public_subnets
cluster_endpoint_public_access = true
cluster_endpoint_public_access_cidrs = local.cidrs
enable_cluster_creator_admin_permissions = true
eks_managed_node_groups = {
main = {
desired_size = 2
instance_types = ["t3.medium"]
}
}
}
provider.tf
provider "aws" {
default_tags {
tags = {
ManagedBy = "terraform"
}
}
region = local.region
profile = local.profile
allowed_account_ids = [local.account_id]
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60.0"
}
}
}
作成されるリソース
VPC関連
-
VPC (
${local.project}-vpc
)- CIDR:
10.0.0.0/16
- アベイラビリティゾーン:
ap-northeast-1a
とap-northeast-1c
- NATゲートウェイが有効
- CIDR:
-
サブネット
- プライベートサブネット:
10.0.1.0/24
(ap-northeast-1a
)、10.0.2.0/24
(ap-northeast-1c
) - パブリックサブネット:
10.0.101.0/24
(ap-northeast-1a
)、10.0.102.0/24
(ap-northeast-1c
)
- プライベートサブネット:
-
インターネットゲートウェイ
- VPCに接続されるインターネットゲートウェイ
-
NATゲートウェイ
- パブリックサブネット内に配置され、プライベートサブネットのインスタンスにインターネットアクセスを提供
-
ルートテーブル
- パブリックおよびプライベートサブネット用のルートテーブルが作成されます。パブリックサブネットにはインターネットゲートウェイへのルートが追加され、プライベートサブネットにはNATゲートウェイへのルートが追加されます。
EKS関連
-
EKSクラスタ
- クラスタ名:
${local.project}-eks
- Kubernetesバージョン:
1.30
- VPC: 上記のVPCに配置されます。
- サブネット: プライベートサブネットにEKSコントロールプレーンが配置されます。コントロールプレーンのENIはパブリックサブネットに作成されます。
- 公開アクセスエンドポイント: 有効 (
cluster_endpoint_public_access = true
) - 公開アクセスのCIDR制限: local.cidrs
- クラスタ名:
-
EKS Managed Node Groups
- ノードグループ名:
main
- インスタンスタイプ:
t3.medium
- デザイアードサイズ: 2台
- ノードが自動的にスケールアップ/ダウンします(最小サイズと最大サイズはデフォルトの設定によります)。
- ノードグループ名:
-
IAMロールとポリシー
- EKSクラスタとノードグループのためのIAMロールとポリシーが作成されます。
-
セキュリティグループ
- EKSクラスタとノードグループのために、必要なセキュリティグループが作成されます。
-
その他のクラスタリソース
- KubernetesのControl Plane Logsの有効化
- OIDCプロバイダー設定(IRSAのため)
2. Kubernetesにk6 Operatorをデプロイ
1. EKSクラスターの設定
~/.kube/config
ファイルが更新され、kubectl
でEKSクラスターにアクセスできるようにする
aws eks --region <region> update-kubeconfig --name <cluster_name>
kubectl
でEKSクラスターに接続を確認
kubectl get nodes
2. k6-operatorのインストール
git clone https://github.com/grafana/k6-operator && cd k6-operator
make deploy
status確認
kubectl get pod -n k6-operator-system
3. テストスクリプト
test.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 10,
duration: '10s',
};
export default function () {
http.get('https://test.k6.io/');
sleep(1);
}
動作確認
k6 run test.js
4. ConfigMapとしてテストスクリプトを追加
kubectl create configmap my-test --from-file test.js
5. カスタムリソースの作成
run-k6-from-configmap.yaml
という名前で以下のYAMLファイルを作成し、ConfigMapからスクリプトを実行する設定を行います
run-k6-from-configmap.yaml
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: run-k6-from-configmap
spec:
parallelism: 4
script:
configMap:
name: my-test
file: test.js
6. テストの実行
-
以下のコマンドを実行してテストを開始します:
kubectl apply -f run-k6-from-configmap.yaml
❯ kubectl get pods ─╯
NAME READY STATUS RESTARTS AGE
run-k6-from-configmap-1-qhxv2 0/1 Completed 0 41s
run-k6-from-configmap-2-s6hwj 0/1 Completed 0 41s
run-k6-from-configmap-3-wp4vh 0/1 Completed 0 41s
run-k6-from-configmap-4-dj658 0/1 Completed 0 41s
run-k6-from-configmap-initializer-d4s8d 0/1 Completed 0 49s
run-k6-from-configmap-starter-xlqwd 0/1 Completed 0 32s
❯ kubectl logs run-k6-from-configmap-1-qhxv2 ─╯
data_received..................: 327 kB 30 kB/s
data_sent......................: 3.7 kB 335 B/s
http_req_blocked...............: avg=35.13ms min=4.35µs med=5.36µs max=332.69ms p(90)=122.27ms p(95)=308.73ms
http_req_connecting............: avg=16.52ms min=0s med=0s max=157.2ms p(90)=57.38ms p(95)=144.93ms
http_req_duration..............: avg=168.31ms min=143.63ms med=158.2ms max=296.06ms p(90)=222.62ms p(95)=289.51ms
{ expected_response:true }...: avg=168.31ms min=143.63ms med=158.2ms max=296.06ms p(90)=222.62ms p(95)=289.51ms
http_req_failed................: 0.00% ✓ 0 ✗ 27
http_req_receiving.............: avg=16.09ms min=76.59µs med=115.66µs max=144.84ms p(90)=56.86ms p(95)=143.85ms
http_req_sending...............: avg=38.14µs min=19.37µs med=28.73µs max=95.16µs p(90)=77.73µs p(95)=91.56µs
http_req_tls_handshaking.......: avg=16.56ms min=0s med=0s max=157.27ms p(90)=57.52ms p(95)=145.44ms
http_req_waiting...............: avg=152.18ms min=143.51ms med=149.19ms max=180.68ms p(90)=159.49ms p(95)=159.64ms
http_reqs......................: 27 2.460681/s
iteration_duration.............: avg=1.2s min=1.14s med=1.15s max=1.49s p(90)=1.35s p(95)=1.45s
iterations.....................: 27 2.460681/s
vus............................: 3 min=0 max=3
vus_max........................: 3 min=3 max=3
-
テストが終了したら、リソースをクリーンアップするために以下を実行します:
kubectl delete -f run-k6-from-configmap.yaml
実行したログなどの収集
k6リソースを見ると、STAGE
がstarted
になっている。
$ kubectl get k6 -n k6-test
NAME STAGE AGE TESTRUNID
k6-sample started 28s
Podは以下のようになっていて、parallelism
で4並列で動かすよう指定していたため、テスト本体は4つ同時に動いている。
$ kubectl get pod -n k6-test
NAME READY STATUS RESTARTS AGE
k6-sample-1-gf698 1/1 Running 0 41s
k6-sample-2-n2rbl 1/1 Running 0 41s
k6-sample-3-tbk6f 1/1 Running 0 41s
k6-sample-4-v657j 1/1 Running 0 41s
k6-sample-initializer-7cxff 0/1 Completed 0 50s
k6-sample-starter-ftdzh 0/1 Completed 0 34s
テスト終了後はSTAGE
がfinished
になる。
$ kubectl get k6 -n k6-test
NAME STAGE AGE TESTRUNID
k6-sample finished 89s
ログを見るとテストの結果を確認することができる
$ kubectl logs -n k6-test k6-sample-1-gf698
✓ http response status code is 200
checks.........................: 100.00% ✓ 3557 ✗ 0
data_received..................: 3.3 MB 56 kB/s
data_sent......................: 450 kB 7.5 kB/s
http_req_blocked...............: avg=4.01ms min=1.8µs med=5.56µs max=270.01ms p(90)=6.9µs p(95)=8.8µs
http_req_connecting............: avg=1.92ms min=0s med=0s max=120.45ms p(90)=0s p(95)=0s
http_req_duration..............: avg=432.43ms min=103.84ms med=124.67ms max=2.93s p(90)=1.59s p(95)=2.09s
{ expected_response:true }...: avg=432.43ms min=103.84ms med=124.67ms max=2.93s p(90)=1.59s p(95)=2.09s
http_req_failed................: 0.00% ✓ 0 ✗ 3557
http_req_receiving.............: avg=125.08µs min=23.3µs med=120.21µs max=3.12ms p(90)=157.28µs p(95)=182.03µs
http_req_sending...............: avg=35.59µs min=7.79µs med=28.69µs max=735.26µs p(90)=51.94µs p(95)=58.07µs
http_req_tls_handshaking.......: avg=2.05ms min=0s med=0s max=126.54ms p(90)=0s p(95)=0s
http_req_waiting...............: avg=432.27ms min=103.71ms med=124.54ms max=2.93s p(90)=1.59s p(95)=2.08s
http_reqs......................: 3557 59.281034/s
iteration_duration.............: avg=436.66ms min=104.08ms med=125.48ms max=2.93s p(90)=1.59s p(95)=2.09s
iterations.....................: 3557 59.281034/s
vus............................: 2 min=0 max=50
vus_max........................: 50 min=50 max=50
Discussion