目的
JMeter はかなり昔からある負荷テストツールです。JMeter が動くホストを複数台構成にして、さらに高負荷をかけることも出来るようになってるのですが、そのために行うサーバー構築や設定が若干面倒です。
今回、JMeter を Docker コンテナに載せて Kubernetes に管理させる、という事をやってみます。それにより、以下のようなメリットがあるのでは無いかと考えています。
- 一度設定が完了してしまえば、再度構築する場合などに楽
- 台数の増減が簡単
- (流行りの k8s を、実際に使いながら勉強できる)
また、テスト結果は Grafana で可視化します。
概要
基本的には以下のレポジトリの内容に沿ってやるのですが、環境などがは一部異なるのと、細かい補足などを随時記載します。
kubernauts/jmeter-kubernetes: Load testing as a service (LTaaS) with Apache Jmeter on kubernetes
環境は
- Amazon Elastic Kubernetes Service (Amazon EKS)
- この上に、JMeter, Grafana, InfluxDB を構築
- クライアントとして eksctl を使用
やることの流れとしては
- クラスターの生成
- 各種ノードを起動
- Grafana のダッシュボードの設定
- Grafana ダッシュボードテンプレートのインポート
- テストシナリオの作成
- テスト
という形です。各手順を順次説明していきます。
手順
クラスターの生成
元のレポジトリーの内容は 既に Kubernetes クラスターが稼働していることが前提になっているため、まずは EKS でクラスターを生成する必要があります。
まずは以下のような JSON ファイルを作成し cluster.yaml
という名前で保存します。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: example-jmeter
region: us-east-1
# 既存の VPC を使用
vpc:
id: "vpc-xxxxxxxxxxxxxxxxx"
subnets:
# public を指定することも可能
private:
us-east-1a:
id: "subnet-xxxxxxxxxxxxxxxxx"
us-east-1c:
id: "subnet-xxxxxxxxxxxxxxxxx"
nodeGroups:
- name: dashboard
instanceType: m5.xlarge
desiredCapacity: 1
privateNetworking: true
- name: jmeter
instanceType: m5.xlarge
desiredCapacity: 3
privateNetworking: true
その上で、以下のコマンドを実行してクラスターを生成します。
eksctl create cluster -f cluster.yaml
eksctl の以下のドキュメントも参照して下さい。
なお、上の yaml は、既存の VPC を使う設定になっています。yaml に vpc
の項目が無い場合、自動で VPC やサブネットが作成されます。その辺りは後ほど説明します。
各種ノードの起動
次に、EKS クラスター内で各種ノードを起動します。以下のコマンドを実行します。
./jmeter_cluster_create.sh
何をやっているかはソースを直接見た方が早いと思いますが、
kubectl create -n <ネームスペース> -f $working_dir/xxxxx.yaml
といったコマンドの羅列です。
Grafana のダッシュボードの設定
こちらもコマンドを実行するだけです。
./dashboard.sh
こちらもシンプルなのでソースを見た方が早いですが、やっている事は主に InfluxDB に対し CREATE DATABASE jmeter
を発行し、ファイルをコピーし、最後の行で Grafana のデータソースを設定しているくらいです。
Grafana ダッシュボードテンプレートのインポート
今まではコマンドラインでの操作でしたが、ここの手順は Grafana の GUI にアクセスして行います。
接続先を確認するために、以下のコマンドを実行します。
kubectl describe -n <ネームスペース名> svc jmeter-grafana
LoadBalancer Ingress
というのがあれば、そのIPアドレスを控えておき、以下の URL にアクセスします。
http://<そのIPアドレス>:3000/
ない場合は、public な IP が無いため直接アクセス出来ません。その場合は、ポートフォワードを使います。まずは以下のコマンドを実行します。
kubectl -n <ネームスペース名> get pod -o wide
そこで、jmeter-grafana の pod 名(NAME
の列に記載されている)を控えておき、以下のコマンドを実行します。(例えば jmeter-grafana-67b57d859f-lhchh
だったとすると)
kubectl -n <ネームスペース名> port-forward jmeter-grafana-67b57d859f-lhchh 3000:3000
その上で、以下の URL にアクセスします。
http://127.0.0.1:3000/
Grafana の管理画面にアクセス出来たら、レポジトリにある GrafanaJMeterTemplate.json というファイルをインポートします。
インポート方法は以下のドキュメントを参照して下さい。
Export & Import | Grafana Documentation
テストシナリオの作成
テストシナリオは GUI で作成した方が楽なので、ローカル環境に JMeter を入れるなどして、JMeter の GUI モードを立ち上げて下さい。
レポジトリーにある cloudssky.jmx
をコピペして修正するのが良いと思いますが、一から作る場合は BackendListener
の設定を忘れないようにして下さい。そうしないと、テスト結果が InfluxDB に保存されません。
Backend Listener に関しては、以下のドキュメントを参照して下さい。
Apache JMeter – User’s Manual: Component Reference
テスト
いよいよテストです。以下のコマンドを実行するだけで OK です。
./start_test.sh
JMeter には、CSV ファイルを読み込んで、それをパラメータにセットする機能があります。1つの用途としては、1つの固定の URL に負荷をかけるのでは無く、例えば以下のような URL で ID 1 と ID 2 を変えて負荷をかけたい場合が挙げられます。
http://example.com/path/to/endpoint?user_id=<ID 1>&content_id=<ID 2>
この場合、ID 1 と ID 2 が入った CSV ファイルを JMeter に渡す事になります。この機能(CSV Data Set Config)の詳細に関しては、JMeter の以下のドキュメントを参照して下さい。
Apache JMeter – User’s Manual: Component Reference
今回、JMeter は k8s 上の pod で動作しますので、テストシナリオと共に CSV ファイルも pod 上にコピーする必要があります。それを行ってくれるのが、同ディレクトリ上にある start_test_csv.sh
です。
補足等
既存の VPC を使うか否か
結論から書くと、本番環境であれば既存の VPC を使った方が良いと思います。その上で、以下を読んでもらえればと思います。
eksctl のドキュメントを見ると、既存の VPC を使う事はあまり推奨されていないように見えます。以下のドキュメントからいくつか抜粋します。
You must ensure to provide at least 2 subnets in different AZs. There are other requirements that you will need to follow, but it’s entirely up to you to address those.
There maybe other requirements imposed by EKS or Kubernetes, and it is entirely up to you to stay up-to-date on any requirements and/or recommendations, and implement those as needed/possible.
If you are in doubt, don’t use a custom VPC. Using
eksctl create cluster
without any--vpc-*
flags will always configure the cluster with a fully-functional dedicated VPC.
ただ、実際のところ、業務で使う場合には、IP アドレス帯などのネットワーク設定は管理しておきたいので、VPC を勝手に作られてしまうのは使いづらいです。
また、上のドキュメントだと AWS のリソースに手動でタグを付けておく必要があると書いてありますが、現在の eksctl では、その辺りも自動でやってくれるようでした。
また、以下にある eksctl の設定サンプルファイルでも、既存 VPC を使ったものがあります。
eksctl/examples at master · weaveworks/eksctl
ということで、既存 VPC を使っても問題無いと判断しました。
public subnet vs. private subnet
VPC は既存のモノを使うとして、subnet は public, private あるいは両方使う、のどれが良いでしょうか。
今回の構成をお手軽に試すのであれば public subnet だけを使うのがハマりどころが少なくて良いと思います。
実際に業務で使う場合には、要件次第としか言えませんね。private subnet を使って問題が発生した場合は、後の方の「トラブルシューティング」の項も参照して下さい。
よくある操作のまとめ
JMeter on Kubernetes に限った内容ではありませんが、良くある操作をまとめました。
JMeter の slave 用 pod の数を変更するには jmeter_slaves_deploy.yaml
の spec
-> replicas
の数を変更し、以下のコマンドを実行します。
kubectl -n <ネームスペース名> apply -f jmeter_slaves_deploy.yaml
ノード数を変更する場合には、以下のコマンドを実行します。
eksctl scale nodegroup --cluster 'example-jmeter' --nodes <ノード数> jmeter --region us-east-1
EKS クラスターをまるごと削除する場合は、以下のコマンドを実行します。
eksctl delete cluster -f cluster.yaml
トラブルシューティング
timed out (after 25m0s) waiting for at least 1 nodes to join the cluster and become ready in “dashboard
クラスター生成時(eksctl create cluster
)にこのようなメッセージが出ました。色々な原因が考えられるのですが、私の場合は VPC のネットワーク設定が間違っていて、private subnet 内のノードから外部への通信が行えていませんでした。
ルーティング、NAT Gateway の設定などを修正したら問題が解消しました。
none or too few private subnets to use with –node-private-networking
同じくクラスター生成時に出たエラーです。理由は、cluster.yaml
の nodeGroups
の設定で privateNetworking: true
にしているにも関わらず、vpc
-> subnets
の下に private
のサブネットが指定されていなかったためでした。(単純なミス)
could not find any suitable subnets for creating the elb
これもクラスター生成時に色々試している時に出ました。以下のように「タグ付けが正しくされていないから」みたいな情報とかもあったのですが、前述の通り、最近のバージョンの eksctl では、手動でのタグ付けは不要です。
Explain why not subnets are found for creating an ELB on AWS · Issue #29298 · kubernetes/kubernetes
こちらも、ネットワーク設定を直したら、エラーが解消しました。
まとめ
かなり長くなりましたが、Amazon EKS でクラスターを生成し、その上で JMeter (+ Grafana)を起動し、簡単に負荷テストを行える環境を作成しました。
手軽に構築できるとは言え、Kubernetes や AWS の基本的な知識が無いと、何か問題が発生した時に手が出ません。Kubernetes の公式ドキュメントなどで基礎知識を得ておくことをお勧めします。(私自身、実際に使えるようになるまでに結構時間がかかってしまいましたが、その分、Kubernetes や EKS の良い勉強になりました。)
また、eksctl は、どんどん改善されているようで、ネット上には古い情報も散見されました。まずは、公式ドキュメントを参照することをお勧めします。