kubectl + gpt のk8sクラスタ診断ツールを触ってみた(k8sgpt)

# はじめに
クラスタの診断をgptを使って行ってくれる`k8sgpt`というツールがリリースされていて、気になったので使ってみました。
[Releases · k8sgpt-ai/k8sgpt](https://github.com/k8sgpt-ai/k8sgpt)  
`k8sgpt analayze`とコマンドをたたくとクラスタ内の問題の表示やその解決策を表示してくれます。


# 必要なもの
- kubectlコマンド(と触れるクラスタ)
- OpenAIのアカウント(APIキー)

# インストール
Mac/Linux/Windowsへのインストールの仕方はREADME上に記載されています。  
Ubuntuの場合以下でインストールできます。  

```
$ curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.2.0/k8sgpt_amd64.deb
$ sudo dpkg -i k8sgpt_amd64.deb
```

インストールできたら以下でバージョンを確認できます。
```
$ k8sgpt version
k8sgpt version 0.2.0
```

# 初期設定
解析に利用するOpenAIのAPIキーを設定していきます。  
```sh
$ k8sgpt generate
# コマンドをたたくとブラウザでOpenAIのAPIキー作成画面が開きます。
# ブラウザの入っていない環境の場合は別途APIキーを作成しておきます。

$ k8sgpt auth
$ k8sgpt auth
Using openai as backend AI provider
Enter openai Key: <APIキーをペースト>
New provider added
key added
```

これで初期設定が完了です。  
設定が完了するとホームディレクトリ配下に`.k8sgpt.yaml`ファイルが作成され先ほど入力したAPIキーの情報などが保存されています。

# 診断
`analyze`で診断できるようなので、とりあえず叩いてみます。  
```
$ k8sgpt analyze

No problems detected
```

特に問題は起こっていないようなので、1つ問題を起こしてみましょう。
```
$ kubectl run nginx --image=nnnnnnnnginx:latest --restart=Never
```

再度診断してみると以下のように問題を発見できます。
```sh
$ k8sgpt analyze       

0 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
```

この段階ではクラスタのAPIから各リソースのConditionとStatusを取得して解析しているだけのようです。
`--explain`オプションでOpenAIに対して取得した情報を送信し、問題の説明を表示できます。  
デフォルトでは送信先(backend)はOpenAIのAPIですが、別のAPIも利用できるようです。(詳しくは調べていませんが・・・)
また、LLaMaなども利用できるようにするEnhancementもあったりしました。

```sh
$ k8sgpt analyze --explain --no-cache
 100% |███████████████████████████████████████████████████████████████████████████████████████████████████████████████| (1/1, 4 it/min)         

0 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
The Kubernetes pod is unable to download the latest version of the Nginx image. 

To resolve this issue, check if the specified image exists in the container registry and ensure that it is accessible. If the image is behind a private registry, make sure you have the necessary credentials to access it. Another workaround is to specify a previous version of the Nginx image that is available in the container registry.
```

また日本語でも表示ができます。結果がキャッシュされるようなので`--no-cache`を指定して改めて結果を取得します。
```sh
$ k8sgpt analyze --language Japanaese --explain --no-cache
 100% |███████████████████████████████████████████████████████████████████████████████████████████████████████████████| (1/1, 2 it/min)         

0 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
このKubernetesエラーメッセージは、コンテナが最新のNginxイメージを取得できなかったことを示しています。これは通常、ネットワークの問題によるものです。

解決策としては、次のようになります。まず、イメージが公開されているDockerレジストリにアクセスできることを確認してください。ネットワーク接続を確認し、必要に応じてプロキシを設定してください。次に、Kubernetesクラスター内のDockerデーモンにアクセスできることを確認してください。

また、イメージを更新することも考慮してください。もし最新バージョンが利用可能であれば、イメージを更新して、同じ名前で新しいタグを作成する必要があります。

エラーメッセージの簡略化：Nginxイメージを取得できなかった

解決策：ネットワーク接続を確認し、必要に応じてプロキシを設定してください。また、新しいタグを作成するために、イメージを更新してください。

# Promptで問い合わせを行っているので同じ問題に対しても毎回表示が同じわけではない
$ k8sgpt analyze --language Japanaese --explain --no-cache
 100% |███████████████████████████████████████████████████████████████████████████████████████████████████████████████| (1/1, 2825 it/s)        

0 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
Kubernetesのエラーメッセージ「Back-off pulling image "nnnnnnnnginx:latest"」を簡単にすると、「nnnnnnnnginx:latest」というイメージが取得できなかったという意味です。

解決方法としては、次のことを確認してください。

1. イメージ名が間違っていないか確認してください。
2. このイメージが存在するリポジトリが正しいかどうか確認してください。
3. インターネット接続が正常であることを確認してください。

これらの問題を解決しても、まだ問題が解決しない場合は、Kubernetesのログを確認してください。可能な原因がログに記載されていることがあります。

```

2つ目の結果はだいぶわかりやすく問題の解決策を指摘してくれていました。

試しにmemoryの制限を20MiにしてみたMySQLのPodを作成してみてOOMKillを発生させた状態でも診断してみました。
今回の結果ですと、解決策の4番目のdescribeコマンドで気づくことができそうですね。

```sh
$ k8sgpt analyze --language Japanaese --explain --no-cache
 100% |█████████████████████████████████████████████████████████████████████████████████████████████████████████████| (2/2, 1 it/min)           

0 default/mysql-7bfbff7b6f-v4jh2(Deployment/mysql)
- Error: back-off 1m20s restarting failed container=mysql pod=mysql-7bfbff7b6f-v4jh2_default(52b558e6-39ff-4cb2-97e1-c2e44f05dd12)
Kubernetesエラーメッセージ「バックオフ1m20s再起動に失敗したコンテナ=mysqlポッド=mysql-7bfbff7b6f-v4jh2_default（52b558e6-39ff-4cb2-97e1-c2e44f05dd12）」は、MySQLコンテナが正常に起動しなかったことを示しています。解決策としては、次の手順を実行することができます。

1. ポッドの状態を確認する
kubectl get pod

2. ログを確認する
kubectl logs mysql-7bfbff7b6f-v4jh2

3. MySQLが起動しているかどうかを確認する
kubectl exec -it mysql-7bfbff7b6f-v4jh2 -- mysql -uroot -p

4. MySQLコンテナの設定を再確認する
kubectl describe pod mysql-7bfbff7b6f-v4jh2

これらのステップを実行して、MySQLコンテナを正常に起動させることができるように問題を特定して解決してください。

1 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
Kubernetesエラーメッセージを簡略化し、日本語で解決策を提供してください："nnnnnnnginx:latest"の画像を引き出すためのバックオフ。

このエラーメッセージは、Kubernetesがイメージの取得に失敗し、自動的に再試行を行っていることを示しています。このエラーは、Docker Hub上のイメージが使用できなくなった場合によく発生します。

解決策は、以下のオプションのいずれかを実行することです。

1. イメージを別の公開レジストリにプッシュします。
2. 別のバージョンのイメージを使用します。
3. Docker Hubにログインするためのアクセストークンを提供します。

これらの手順を実行しても問題が解決しない場合は、コンテナレジストリへの接続を確認し、Kubernetes APIサーバーに正しく接続されていることを確認してください。
```

2023/4現時点以下のAnalyzerが実装されており、対応するリソースの問題の診断を行えるようです。
それぞれのAnalyzerが各リソースの情報を取得し、リソースに合わせたテンプレートのPromptに情報を埋め込んでリクエストを行っていました。  

```
Built in analyzers
・Enabled by default
 ・podAnalyzer
 ・pvcAnalyzer
 ・rsAnalyzer
 ・serviceAnalyzer
 ・eventAnalyzer
 ・ingressAnalyzer
・Optional
 ・hpaAnalyzer
 ・pdbAnalyzer
```

どれをAnalyzeするかは`k8sgpt filters`コマンドで設定できます。
```sh
# デフォルトでは以下のようになっています
$ k8sgpt filters list  
Active: 
> Ingress
> Pod
> ReplicaSet
> PersistentVolumeClaim
> Service
Unused: 
> HorizontalPodAutoScaler
> PodDisruptionBudget
```

Serviceも検知するようなので問題を起こしてみましょう。

```sh
# labelでタイポした想定で、宛先のPodが存在しないServiceを作成
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
    role: sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      role: sample
  template:
    metadata:
      labels:
        app: nginx
        role: sample
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-deployment-svc
spec:
  selector:
    app: nginxx
    role: sample
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
EOF
```

`k8sgpt analyze`で診断してみると、以下のようにServiceのエラーも検知しています。

```sh
$ k8sgpt analyze

0 default/nginx-deployment-svc(nginx-deployment-svc)
- Error: Service has no endpoints, expected label app=nginxx
- Error: Service has no endpoints, expected label role=sample


1 default/nginx(nginx)
- Error: Back-off pulling image "nnnnnnnnginx:latest"
```

`k8sgpt filters`でPodを対象外にし、再度診断してみます。

```sh
# Podを診断の対象外に設定
$ k8sgpt filters remove Pod
Filter(s) Pod removed

# 対象を再確認 
$ k8sgpt filters list
Active: 
> ReplicaSet
> PersistentVolumeClaim
> Service
> Ingress
Unused: 
> Pod
> HorizontalPodAutoScaler
> PodDisruptionBudget

# 再度診断するとPodは対象外のため検知されず
$ k8sgpt analyze       

0 default/nginx-deployment-svc(nginx-deployment-svc)
- Error: Service has no endpoints, expected label app=nginxx
- Error: Service has no endpoints, expected label role=sample
```


NodeのAnalyzerもenhancementとして挙げられていたりするので、それが実装されればある程度の範囲はカバーできそうです。
リリースされたばかりではありますが、あまりクラスタを触ったことがない場合はk8sgptを使うとトラブルシューティングに役立ちそうです。  

# セキュリティ面について
以下にOpenAIに送られるデータについての話がありました。  
[question: Could you explain how you treat cluster data?](https://github.com/k8sgpt-ai/k8sgpt/issues/139)
上記にもある通り`k8sgpt analyze --explain`で個人を特定できる情報が送られるような例として、コンテナイメージ名が上げられたりしています。  
リソースのConditionやStatusを取得するとありましたが他にもざっと確認してみたところ、Labelやリソース名、Namespace名などもOpenAIに送られる可能性があります。 
こちらに関してはv0.2.1で`--anonymize`オプションが追加され匿名化することができるようになっていました。

OpenAI側でのデータの取り扱いに関しては基本的には使われないようです。  
詳しくは以下で調査されていたのでそちらを参考にしてください。

https://qiita.com/ysv/items/cb39ae4d96c1c8a73f59

いずれにしても実際に使う場合には問題無いか確認してから使う方がよさそうです。