みなさんこんにちは!内製開発チームの杉山です!
だんだん寒さが本格的になってきましたね。寒いといえば(?)、私とSREチームの迫田は、11月にソルトレイクシティで行われる KubeCon + CloudNativeCon NA 2024 に参加する予定です!初めての KubeCon, とても楽しみです…!11月のソルトレイクシティはとっても寒そうですね。現地に行かれる方は、ぜひ仲良くしていただけたら嬉しいです🙇♂️
さて、今回は負荷試験の環境を Amazon EKS 上に構築して Datadog と連携したので、そのことについて書いてみます! xk6 拡張機能が無いと連携出来ないということで、そのあたりも振り返ってみます。
負荷試験実施にあたって
負荷試験を実施する際には、以下のようなことを考えるかと思います。
- シナリオを記述する言語
- 実施する環境
- 実施結果の確認方法
- and more...
結論として、当チームでは k6 を採用したのですが、上記を鑑みても k6 は諸々揃っているなと考えました。
- シナリオは馴染みのある Javascript で記述可能(慣れてる!
- 実施環境は Kubernetes 上に Operator を利用して構築可能、分散実行もできる(便利!
- 実施結果は Datadog にメトリクスを送ることでダッシュボードで閲覧可能(見やすい!
- Operator は Grafana Labs が提供(何気に嬉しいポイント
今回はせっかくの Kubernetes 環境があるので Operator を利用したのですが、Datadog の導入も Operator を利用しましたし、どんどん Operator 頼みになっているなぁと感じている今日この頃です。
k6 Operator とは
k6 を提供する Grafana Labs が公式で提供している Kubernetes Operator です。これを利用することで、Kubernetes クラスター内で分散テストが実行できます。
当チームでは Argo CD + Helm を利用してデプロイしていますが、サクッと導入できて本当に便利ですね。以下のようなマニフェストを作成してプラットフォーム用のノードに Pod がスケジューリングされるようにしています。
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: finalizers: - resources-finalizer.argocd.argoproj.io name: k6-operator namespace: argocd spec: project: default source: repoURL: https://grafana.github.io/helm-charts chart: k6-operator targetRevision: 3.8.0 helm: releaseName: k6-operator valuesObject: tolerations: - key: "dedicated" operator: "Equal" value: "platform" effect: "NoSchedule" affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: service-name operator: In values: - platform podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - k6-operator topologyKey: topology.kubernetes.io/zone destination: namespace: k6-operator-system server: https://kubernetes.default.svc
あとはカスタムリソースである TestRun
で実行環境を定義し、テストシナリオを Javascript で記述するだけ!うーん、便利です。
Datadog との連携
Datadog との連携もサクサク…と思っていましたが、ちょっと工夫が必要でした。主に以下の流れで Datadog 連携を実現しています。
- Datadog Agent にて
dogstatsd
を有効化する。 - xk6 拡張機能を利用する Dockerfile を作成してコンテナリポジトリ(当チームでは Amazon ECR) に PUSHする。
TestRun
カスタムリソースに 1. で作成したイメージを利用するように記述する。TestRun
カスタムリソースでarguments
とenv
を追加する。TestRun
を実行し、Datadog にメトリクスが送信されていることを確認!
Datadog Agent についての設定は以下に記載があります。
DogStatsD は、Datadog Agent に付属するメトリクス集計サービスです。これがないと始まらないので、Datadog Agent のマニフェストにさくっと追加します。(ここでは Operator 利用を前提としています)
features: dogstatsd: hostPortConfig: enabled: true
また、k6 実行後に、Datadog Agent のホストIP (k6 自身がデプロイされているノードのIP) を与える必要がありますが、これは後ほど…
xk6 extensions の利用
ここから本格的に k6 との連携を行っていきます。まずは k6 の公式ページを見ると、冒頭に目立つ WARNING
の文字が。(2024年10月8日現在)
Warning
The built-in StatsD output has been deprecated on k6 v0.47.0 and scheduled to be removed in v0.55.0. You can continue to use this feature by using the xk6-output-statsd extension, or using the OpenTelemetry output depending on your use case.
For more information on the reason behind this change, you can follow this issue in the k6 repository.
どうやら xk6-output-statsd extension
というものが必要なようです。ここで、そもそも xk6 extension とは?となった私。以下のページを見ることに。
Explore k6 extensions という意味だったのですね(知らなかった…!)。この拡張機能は、k6 の developer, OSS developer community によって開発されているようです。自分が必要なものも開発できるようで…我々は恩恵に預かってばかりで頭が上がりません。
で、Datadog へ連携する場合は、先ほどの xk6-output-statsd extension
が必要ということですね。これは xk6
コマンドでビルドし、バイナリとして利用することが可能です。ビルド方法については以下の StatsD
ページに記載があります。
# sample # Install xk6 go install go.k6.io/xk6/cmd/xk6@latest # Build the k6 binary xk6 build --with github.com/LeonAdato/xk6-output-statsd
サンプルではコマンドが提供されていますが、ここは Kubernetes 上で実行するために、イメージを用意したいところ。ですので、以下のように golang ベースのイメージでビルド後、grafana k6 イメージを上書きする形で Dockerfile を用意しました。(もっと良い方法があるかもしれませんが…
# Build FROM golang:1.23.2-bookworm as builder RUN go install go.k6.io/xk6/cmd/xk6@latest RUN xk6 build \ --with github.com/LeonAdato/xk6-output-statsd@latest \ --with github.com/avitalique/xk6-file@latest \ --output /k6 # Override FROM grafana/k6:latest COPY --from=builder /k6 /usr/bin/k6
そして、このイメージを TestRun
カスタムリソースで呼び出すようにするわけですが、まだ arguments
と env
の記述が足りません。そもそも、それぞれ何を記述すれば良いのでしょうか。
改めて k6 と Datadog の Integration 方法を紹介するページに記載されている Run the k6 test
を見てみます。
$ K6_STATSD_ENABLE_TAGS=true k6 run --out output-statsd script.js
環境変数で K6_STATSD_ENABLE_TAGS
を定義し、 arguments
として --out output-statsd
を指定していますね。なので、これを TestRun
カスタムリソースのマニフェストに記載します。
level=error msg="Couldn't flush a batch" error="write udp 127.0.0.1:39641->127.0.0.1:8125: write: connection refused"
むむ・・・自分自身の 8125 ポートにアクセスしようとしていますね・・・改めて以下を確認すると、 K6_STATSD_ADDR
の初期値が localhost:8125
になっているのが原因のようです。
StatsD | Grafana k6 documentation
Address of the statsd service, currently only UDP is supported. The default value is localhost:8125.
ここは Datadog Agent にしなくてはならないので、これも TestRun
マニフェストに記載する必要がありそうです。
そんなわけで、前述したホストIPも追加したマニフェストは以下のようになりました。
apiVersion: k6.io/v1alpha1 kind: TestRun metadata: name: load-test-sample namespace: load-test-sample spec: parallelism: 2 # 公式ドキュメントに記載されていた`--out output-statsd`を arguments で指定. # arguments の type は string なので注意. arguments: --out output-statsd runner: # xk6 をビルドして作成した Docker イメージを指定. image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/k6-extented:20240101 env: # ここから環境変数を定義する. # K6_STATSD_ADDR では Datadog Agent サービスを指定. - name: K6_STATSD_ADDR value: "datadog-agent.datadog.svc.cluster.local:8125" # 公式ドキュメントに記載されたものを指定. - name: K6_STATSD_ENABLE_TAGS value: "true" # Datadog Agent のホストIPを指定. - name: DD_AGENT_HOST valueFrom: fieldRef: fieldPath: status.hostIP script: configMap: name: load-test-sample-scenario-001 file: test01.js
これまで見てきたものを全部記載してみました!ちなみに runner.image
など、どうやって指定するかについては、以下に全量があります。
驚きの6,000行弱…これを実装された方に敬意しかありません。
ここまでの結果・・・
さて、ここまでやってみたところ、無事に Datadog に連携がされていました!
あとはダッシュボードを加工したり、色々遊び甲斐(!?)がありますね!
まとめ
今回は Kubernetes 上に構築した k6 から、実行結果を Datadog に連携するまでを書いてみました!この環境を使うことで、今後の負荷試験が捗ると良いなあ、と思っています。ただ、パイプラインの整備が出来ていなかったり、まだまだ改善の余地があるので、これからも継続的に良いものにしていきたいです💪
余談・・・
以下の k6 Operator バージョンを導入しようとしたところ、Argo CD + Helm の構成でエラーが発生してしまいました。
k6-operator version or image 0.0.17 Helm chart version (if applicable) 3.9.0
調べたところ、このバージョンから values.schema.json
を導入したようで、当チームのマニフェストでは affinity
や toleration
にてエラーが発生している模様。
じゃあバージョンを戻すか…という気持ちにもなりましたが、こういうときに issue を上げずにどうするのかと。いつまでも甘えてばかりじゃ駄目だと考えて、Issue を起票してみました。
たったこれだけで貢献したとは言えませんが、これからも Kubernetes とエコシステムと共に歩むにあたって、積極的に出来ることからやっていきたいな、と思っています!
それでは、最後までお読みいただき、ありがとうございました!
当チームは積極的な採用を行っています!もしこうした環境やチームに魅力を感じる方がいらっしゃいましたら、ぜひお気軽にお話をしましょう!
アプリケーションエンジニアはこちらから! www.wantedly.com
モバイルアプリエンジニアはこちらから! www.wantedly.com
SRE はこちらから! www.wantedly.com