以前、Helm で locust をインストールしたが、今回は EKS に CDK でインストールする。CDK だとクラスタの作成からできるので cdk deploy で一気に環境が整う。
KubernetesにHelmでLocustによる分散負荷試験環境を立てる - sambaiz-net
$ npm run cdk -- --version
1.62.0 (build 8c2d7fc)
まず VPC と Cluster を作成する。mastersRole をユーザーが assume して kubectl コマンドを実行できるように Principal に AWS アカウントも入れている。
その後、実行するタスクを記述したスクリプト locustfile の ConfigMap を作成し、 これを Chart の worker.config.configmapName で参照する。キー名を間違えがち。 Chart のリポジトリは Helm Hub のもの。
追記 (2020-12-21): 以前はHelm Hubの https://kubernetes-charts.storage.googleapis.com/ を参照していたが、helm/charts リポジトリが deprecated になり削除されてしまったので、archiveを参照するようにした。
追記 (2022-12-31): 今は AmazonEKSServicePolicy を紐づける必要はない。
import * as cdk from '@aws-cdk/core';
import { Cluster, KubernetesVersion, DefaultCapacityType } from '@aws-cdk/aws-eks'
import { Vpc, SubnetType, InstanceType } from '@aws-cdk/aws-ec2'
import { Role, ManagedPolicy, ServicePrincipal, AccountPrincipal, CompositePrincipal } from '@aws-cdk/aws-iam'
import * as fs from 'fs';
export class TryEksStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new Vpc(this, 'vpc', {
cidr: '10.0.0.0/16',
maxAzs: 2,
subnetConfiguration: [
{
cidrMask: 18,
name: 'public',
subnetType: SubnetType.PUBLIC,
},
{
cidrMask: 18,
name: 'private',
subnetType: SubnetType.PRIVATE,
},
]
})
cdk.Tags.of(vpc).add("Name", this.stackName)
const mastersRole = new Role(this, 'masters-role', {
assumedBy: new CompositePrincipal(
new ServicePrincipal('eks.amazonaws.com'),
new AccountPrincipal(this.account)
),
managedPolicies: [
ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSClusterPolicy'),
ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSServicePolicy'),
]
})
const cluster = new Cluster(this, 'cluster', {
vpc,
mastersRole,
clusterName: '<cluster_name>',
version: KubernetesVersion.V1_17,
defaultCapacity: 2,
defaultCapacityInstance: new InstanceType('m5.large')
})
const configmap = {
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: {
name: 'locust-worker-configs',
},
data: {
'tasks.py': fs.readFileSync('lib/tasks.py').toString(),
},
}
cluster.addManifest('locust-worker-configmap', configmap)
cluster.addChart('locust-chart', {
chart: 'locust',
repository: 'https://charts.helm.sh/stable',
version: '1.2.1',
wait: true,
values: {
master: {
config: {
'target-host': 'https://example.com'
}
},
worker: {
replicaCount: 2,
config: {
configmapName: configmap.metadata.name,
}
}
}
})
}
}
イメージのバージョンを最新の 1.x 系にしたところ、 現状のChartが設定する LOCUSTFILE_PATH を読んでくれず Could not find any locustfile! になってしまったのでデフォルトの 0.9 で動かしている。 locustfile の書き方が少し異なるのでバージョンを上げたい場合は Chart を持ってきて編集するか自前のイメージを参照する。
$ cat lib/tasks.py
from locust import HttpLocust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def index(self):
self.client.get("/")
class MyUser(HttpLocust):
task_set = MyTaskSet
min_wait = 5
max_wait = 15
デプロイすると update-kubeconfig するコマンドが Outputs に出るので実行する。Chart がインストールされ Locust が起動していることが確認できる。
$ npm run cdk -- deploy
...
Outputs:
TryEksStack.clusterConfigCommand30DB378E = aws eks update-kubeconfig --name <cluster_name> --region <region> --role-arn <masters_role_arn>
TryEksStack.clusterGetTokenCommand09C244B5 = aws eks get-token --cluster-name <cluster_name> --region <region> --role-arn <masters_role_arn>
$ $(aws cloudformation describe-stacks --region <region> --stack-name <stack_name> | jq -r '.Stacks | .[] | .Outputs | reduce .[] as $i ({}; .[$i.OutputKey] = $i.OutputValue) | to_entries | map(select(.key | startswith("clusterConfigCommand"))) | .[0].value')
$ kubectl config view
apiVersion: v1
...
current-context: <cluster_arn>
kind: Config
preferences: {}
users:
- name: <cluster_arn>
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
args:
- --region
- <region>
- eks
- get-token
- --cluster-name
- <cluster_name>
- --role
- <masters_role>
command: aws
env:
- name: AWS_PROFILE
value: <profile_name>
$ helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
tryeksstackclusterchartlocustchart1abdd876 default 1 2020-09-16 07:51:53.672161109 +0000 UTC deployed locust-1.2.1 0.9.0
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
tryeksstackclusterchartlocustchart1abdd876-master-7fd8998cn4w8z 1/1 Running 0 4m9s
tryeksstackclusterchartlocustchart1abdd876-worker-58b74b6bsgctk 1/1 Running 1 4m9s
tryeksstackclusterchartlocustchart1abdd876-worker-58b74b6bsltvr 1/1 Running 0 4m9s
$ kubectl port-forward $(kubectl get pod -l "component=master" --template '{{(index .items 0).metadata.name}}') 8089
$ open http://localhost:8089
次のようなエラーが出た場合、bootstrapして CDKTookKit stackをデプロイする。
Error: This stack uses assets, so the toolkit stack must be deployed to the environment
$ npm run cdk -- bootstrap
後片付けする。
$ npm run cdk -- destroy
EKS上のLocustから負荷をかける際のリソースの割り当てやインスタンスタイプの調整 - sambaiz-net
CDKでECS(EC2)上にLocust masterとworkerのServiceをデプロイしCloud Mapで名前解決させる - sambaiz-net