k9sで手軽にAPIの負荷試験

# TL; DR

- k9sの `benchmark` 機能を使用
- `type: NodePort`のServiceを用意
- 試験内容をconfigファイルに書けば、上記Serviceに対し負荷試験ができる！
- https://github.com/derailed/k9s#benchmark-your-applications

![bench.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/12d5bc10-9667-3b20-c172-9bee0da2d590.png)

# はじめに

k9s は、Kubernetesクラスタを扱うTUI（kubectlのUI版）です。

![intro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/539103f5-78f8-1407-9d8d-f55a4d68e5b5.png)

https://github.com/derailed/k9s


リソースを一覧で確認できるほか、ショートカットキーでpodのkillやログ確認等手軽に行うことができます。本記事では、k9sでpodのAPIの負荷試験を行うBenchmark機能について紹介します。

# バージョン

- k9s: `v0.25.18`

# 準備
## 検証するPod

httpbinのイメージで検証しました。[httpbin.org](https://httpbin.org/) は様々なテスト用WebAPIを備えているウェブサイトで、今回はそのイメージを使用しています。

https://hub.docker.com/r/kennethreitz/httpbin/

```yaml:deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - name: httpbin
        image: kennethreitz/httpbin
        ports:
        - containerPort: 80
```

## `type: NodePort` のServiceを用意

続いて、負荷試験を行うために、上記PodにつながるServiceを用意します。このとき、Cluster外から疎通できるよう **Serviceのtypeを `NodePort` か `LoadBalancer`にする必要があります**。

```yaml:service.yml
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  type: NodePort
  selector:
    app: httpbin
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30000
```

（ちなみに、`type: ClusterIP` のものを使用すると `You must select a reachable service` とエラーが発生しました）

READMEではPodでもできると書いているのですが、手元ではうまくいきませんでした...

## (kindを使う場合) nodePortをホストのポートに紐づける

開発環境等でkindのclusterを使う場合は、nodePortをホストのポートに紐づける必要があります。上記Serviceが使う30000番をホストの30000番に紐づけます。

```yaml:kind.yml
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
    listenAddress: "0.0.0.0"
    protocol: tcp
- role: worker
```

作ったマニフェストを、cluster作成時に指定します。

```bash
$ kind create cluster --config kind.yml
```

## 試験内容をconfigファイルに書く

いよいよ本題の負荷試験です。ベンチマークの設定を `$XDG_CONFIG_HOME/k9s/bench-<k8s_context>.yml` に記載します。
個人的には、 `$XDG_CONFIG_HOME=$HOME` として、k9sのconfigと同じディレクトリに入れるのがおすすめです。

```:configファイルの場所
$ k9s info
 ____  __.________
|    |/ _/   __   \______
|      < \____    /  ___/
|    |  \   /    /\___ \
|____|__ \ /____//____  >
        \/            \/

Configuration:   /home/syuparn/k9s/config.yml
Logs:            /tmp/k9s-syuparn.log
Screen Dumps:    /tmp/k9s-screens-syuparn
```

yamlには、serviceごとのリクエスト数やパス等を指定します。

```yaml:~/k9s/bench-kind-kind.yml
benchmarks:
  services:
    default/httpbin: # namespace/service
      concurrency: 2
      requests: 20
      http:
        method: GET
        host: 127.0.0.1 # ノードのホスト
        path: /get
```

# 使ってみる

負荷試験を実行します。k9sを起動して、`:service` でService一覧を開きます。試験をしたいServiceにカーソルを合わせて `Ctrl + L` で負荷試験が開始されます。

![bench.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/12d5bc10-9667-3b20-c172-9bee0da2d590.png)

結果は `:bench` で確認できます。

![benchlist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/b503e5bc-f1bb-8612-f9c3-3f9de0048120.png)

レスポンス時間の分布やステータスコードの割合が一目瞭然です。

![detail1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/54d45bda-8f57-824d-86b5-6d4a5792da74.png)
![detail2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/661c0d41-4df2-e4a4-cb6d-6fa4c6c8106d.png)


せっかくなので、負荷を上げて失敗したパターンも見てみましょう。

```yaml:~/k9s/bench-kind-kind.yml
benchmarks:
  defaults:
    concurrency: 1
    requests: 5
  services:
    default/httpbin:
      concurrency: 2000
      requests: 2000
      http:
        method: GET
        host: 127.0.0.1
        path: /get
```

![fail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/e7b4ca00-d235-fcd9-6c58-4ee27e064da4.png)

![faildetail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/08c46c44-3dc4-baf1-6467-e23bc960d22a.png)

APIの前にクライアント側がダウンしてしまったようです :innocent:

# おわりに

以上、k9sで負荷試験を行う方法の紹介でした。
nodePortを用意する手間はありますが、ポチポチやるだけでベンチマークが取れるので検証に活用できそうです。