k8sgpt + LocalAI で k8s クラスタ分析を試してみる
概要
k8sGPT は AI を利用して k8s クラスタの問題点やトラブルシュートを行うためのプロジェクトです。最初の commit が 2023 年 3 月と比較的歴史の浅いプロジェクトですが、2023 年 12 月に CNCF の sandbox プロジェクトに採用され、現時点で github start ~ 5k 程となっています。
k8sGPT の特徴の一つとして ChatGPT や大手クラウドプロバイダーの AI 系サービスだけでなく、LocalAI や ollama 等のローカルで構築可能な LLM も利用できる点があります。これによりデータの機密性の観点からパブリックな AI サービスの利用が難しい場合や、ローカルで用意したモデルを使って分析を行いたいような場合に最適です。サポートしている AI は ドキュメントを参照 。
今回はローカルに構築した LocalAI と組み合わせて使ってみます。
環境構築
LocalAI の構築
LocalAI は docker や kubernetes 上で構築できますが、ここでは手軽さを重視して docker を使用します。
docker イメージは公式のものが用意されていますが、用途によっていくつかイメージタグが分かれています。分類としては大きく分けて以下のようになっています (詳細は https://localai.io/basics/container/ を参照)。
- GPU を使うか CPU のみを使うか
- 事前に設定済みのモデルを使用するか
今回は 設定済みのモデルを使用し、CPU のみ の設定で行うため、localai/localai:latest-aio-cpu
のイメージタグを使用します。
docker-compose.yml
の例が Usage や Github にあるのでこれを参考に作成。
services:
api:
container_name: localai
image: localai/localai:latest-aio-cpu
ports:
- 8080:8080
environment:
LOCALAI_API_KEY: test
volumes:
- ./models:/build/models:cached
LocalAI は様々な設定項目がありますがここでは基本的にデフォルト設定を使用します。
また、認証されたリクエストのみを受け付けるために LOCALAI_API_KEY
に api kye を設定します。通常の api key と同様に推測されにくいランダムな文字列が推奨されますが、簡単のため test
に指定。
docker-compose up -d
でコンテナを起動すると https://localai.io/basics/container/#all-in-one-images に記載の各モデルのダウンロードが行われます。docker logs localai
のコンテナログより進捗が確認できます。
ダウンロードが完了してログに LocalAI API is listening! Please connect to the endpoint for API documentation. endpoint=http://0.0.0.0:8080
が表示されるとリクエストを受け付けるようになるので、Try it out にある api を実行して動作を確認します。
今回は api key を設定しているので、ヘッダーに指定しないリクエストは拒否されます。
$ curl http://192.168.3.204:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{ "model": "gpt-4", "messages": [{"role": "user", "content": "How are you doing?"}] }'
{"message":"Authorization header missing"}%
"Authorization: Bearer [api_key]"
を指定するとリクエストが通ります。
$ curl http://192.168.3.204:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer test" \
-d '{ "model": "gpt-4", "messages": [{"role": "user", "content": "How are you doing?"}] }'
{
"created": 1723306961,
"object": "chat.completion",
"id": "fc893abe-6ae6-4ff8-856b-dfda6ed41138",
"model": "gpt-4",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "Hello! I'm doing well, thank you for asking. How about you? How can I assist you today?"
}
}
],
"usage": {
"prompt_tokens": 14,
"completion_tokens": 24,
"total_tokens": 38
}
}
LocalAI 側のコンテナログでアクセスログを確認可能。 ip=192.168.3.30
からの通信が上記のリクエストに対応。
10:08AM INF Success ip=127.0.0.1 latency="71.495µs" method=GET status=200 url=/readyz
10:08AM WRN Client error ip=192.168.3.30 latency="77.404µs" method=POST status=401 url=/v1/chat/completions
10:08AM INF Trying to load the model 'b5869d55688a529c3738cb044e92c331' with the backend '[llama-cpp llama-ggml gpt4all llama-cpp-fallback rwkv piper stablediffusion whisper huggingface bert-embeddings /build/backend/python/openvoice/run.sh /build/backend/python/parler-tts/run.sh /build/backend/python/vllm/run.sh /build/backend/python/vall-e-x/run.sh /build/backend/python/transformers-musicgen/run.sh /build/backend/python/petals/run.sh /build/backend/python/bark/run.sh /build/backend/python/sentencetransformers/run.sh /build/backend/python/exllama2/run.sh /build/backend/python/sentencetransformers/run.sh /build/backend/python/coqui/run.sh /build/backend/python/transformers/run.sh /build/backend/python/rerankers/run.sh /build/backend/python/autogptq/run.sh /build/backend/python/exllama/run.sh /build/backend/python/mamba/run.sh /build/backend/python/diffusers/run.sh]'
10:08AM INF [llama-cpp] Attempting to load
10:08AM INF Loading model 'b5869d55688a529c3738cb044e92c331' with backend llama-cpp
WARNING: failed to read int from file: open /sys/class/drm/card0/device/numa_node: no such file or directory
WARNING: error parsing the pci address "virtio0"
10:08AM INF [llama-cpp] attempting to load with AVX2 variant
10:08AM INF [llama-cpp] Loads OK
10:09AM INF Success ip=192.168.3.30 latency=28.564574887s method=POST status=200 url=/v1/chat/completions
K8sGPT の構築
k8sGPT は CLI でコマンドを実行して解析する方法、または k8s クラスタに operator をデプロイして分析する方法がありますが、ここでは Operator を使用します。
Operator は helm でインストールできます。
helm repo add k8sgpt https://charts.k8sgpt.ai/
helm repo update
helm install k8sgpt k8sgpt/k8sgpt-operator -n k8sgpt-operator-system --create-namespace
次に kind: K8sGPT
のカスタムリソースを作成します。これが backend provider
と呼ばれる backend (ここでは LocalAI) と通信してクラスタ内の分析を行うリソースとなります。
先ほど作成した LocalAI の api key を secret に作成。
kubectl create secret generic k8sgpt-localai-secret --from-literal=api-key=test -n k8sgpt-operator-system
LocalAI を backend に指定するには、Github の例 に従ってマニフェストを用意します。変更が必要な箇所は以下。
properties | Description | Value |
---|---|---|
backend | 通信先の backend provider 名称を指定。 | localai |
model | 通信先 backend provider で分析に使用するモデルの名称を指定。LocalAI では text Generation のモデル名が gpt-4 になっているのでこれを指定。 |
gpt-4 |
baseUrl | 通信先 backend provider のエンドポイントを指定 | http://192.168.3.204:8080/v1 |
version | K8sGPT のバージョンを指定。現時点では v0.3.40 が最新版 | v0.3.40 |
apiVersion: core.k8sgpt.ai/v1alpha1
kind: K8sGPT
metadata:
name: k8sgpt-localai
namespace: k8sgpt-operator-system
spec:
ai:
enabled: true
model: gpt-4
secret:
name: k8sgpt-localai-secret
key: api-key
backend: localai
baseUrl: http://192.168.3.204:8080/v1
noCache: false
version: v0.3.40
デプロイすると operator が作成を検知して k8sGPT pod が起動します。
$ k get pod
NAME READY STATUS RESTARTS AGE
k8s-operator-k8sgpt-operator-controller-manager-69896dc68dmjg2j 2/2 Running 0 69s
k8sgpt-localai-67b4bd6497-jj8wl 1/1 Running 0 49s
分析
上記で使う準備ができたので、ドキュメント にある以下のマニフェストをデプロイしてエラーを発生させます。
apiVersion: v1
kind: Pod
metadata:
name: broken-pod
namespace: default
spec:
containers:
- name: broken-pod
image: nginx:1.a.b.c # イメージタグが不正なので pod が起動しない
livenessProbe:
httpGet:
path: /
port: 81
initialDelaySeconds: 3
periodSeconds: 3
デプロイ後に少し待つと分析が完了し、結果が results.core.k8sgpt.ai
リソースとして作成されます。
$ k get results.core.k8sgpt.ai
NAME KIND BACKEND
argocdargocdapplicationcontroller StatefulSet localai
backstagebackstagefront Service localai
backstagesamplenginxsvc Service localai
defaultbrokenpod Pod localai
分析の詳細は yaml の spec から確認できます。分析結果としてはイメージ pull に失敗していること、その対処方法が提案されています。
$ k get results.core.k8sgpt.ai defaultbrokenpod -o yaml
apiVersion: core.k8sgpt.ai/v1alpha1
kind: Result
metadata:
creationTimestamp: "2024-08-11T10:25:45Z"
generation: 1
labels:
k8sgpts.k8sgpt.ai/backend: localai
k8sgpts.k8sgpt.ai/name: k8sgpt-localai
k8sgpts.k8sgpt.ai/namespace: k8sgpt-operator-system
name: defaultbrokenpod
namespace: k8sgpt-operator-system
resourceVersion: "8013182"
uid: ae75161d-8d96-42e3-a80e-c931ccc96352
spec:
backend: localai
details: |-
Error: The Kubernetes container is unable to pull the specified image "nginx:1.a.b.c" due to a network issue or image availability problem.
Solution: 1) Check your internet connection. 2) Verify the image is available and tagged correctly. 3) Retry the image pull operation. If the problem persists, consider using a different image version.
error:
- text: Back-off pulling image "nginx:1.a.b.c
kind: Pod
name: default/broken-pod
parentObject: ""
status:
lifecycle: historical
k8sgpt pod は server mode で起動しているため、分析結果は grpc を使うことでクラスタ内外からも取得できます。
k8sgpt pod 作成時に svc も作成されるので CLUSTER-IP
を確認。
$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8sgpt-localai ClusterIP 10.109.241.92 <none> 8080/TCP 10m
クラスタ内から上記の ip に対して grpcurl を実行すると json 形式で結果を取得できます。内容は上記の result の spec.error[].text
となっています。
$ grpcurl -plaintext -d '{"namespace": "default"}' 10.107.21.110:8080 schema.v1.ServerService/Analyze
{
"status": "ProblemDetected",
"problems": 1,
"results": [
{
"kind": "Pod",
"name": "default/broken-pod",
"error": [
{
"text": "Back-off pulling image \"nginx:1.a.b.c\""
}
]
}
]
}
ドキュメントによると explain: true
を指定すると詳細も合わせて取得できそうなのですが、これを指定すると何故か pod がエラーとなり CrashLoopBackOff
で起動しなくなります。
$ grpcurl -plaintext -d '{"explain": true, "namespace": "default"}' 10.107.21.110:8080 schema.v1.ServerService/Analyze
ERROR:
Code: Unavailable
Message: error reading from server: EOF
$ k logs k8sgpt-localai-67b4bd6497-qcmfq k8sgpt
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x261b43b]
goroutine 1 [running]:
github.com/k8sgpt-ai/k8sgpt/cmd/serve.init.func1(0xc0001db000?, {0x2f83ad6?, 0x4?, 0x2f83ada?})
/workspace/cmd/serve/serve.go:152 +0x5db
github.com/spf13/cobra.(*Command).execute(0x5361b40, {0x53f9000, 0x0, 0x0})
/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:989 +0xab1
github.com/spf13/cobra.(*Command).ExecuteC(0x535d920)
/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1117 +0x3ff
github.com/spf13/cobra.(*Command).Execute(...)
/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1041
github.com/k8sgpt-ai/k8sgpt/cmd.Execute({0x37e78ec?, 0x0?}, {0x37e78ed?, 0x51693c0?}, {0x37e78ee?, 0xc0000061c0?})
/workspace/cmd/root.go:59 +0x91
main.main()
/workspace/main.go:25 +0x3d
エラー内容を github で検索するといくつか issue や PR が見つかるので、こちらは近いうちに修正されるかもしれません。
このクラスタは backstage の記事を書いた際に使用したものを流用しているため argocd や backstage 関連のリソースがいくつかデプロイ済みとなっていますが、そちらに関しても問題が検出されているので見てみます。
argocd に関する問題では argocd-application-controller
という StatefulSet が存在しない svc argocd-application-controller
を使用しているという指摘になっています。
- apiVersion: core.k8sgpt.ai/v1alpha1
kind: Result
metadata:
creationTimestamp: "2024-08-11T10:25:45Z"
generation: 1
labels:
k8sgpts.k8sgpt.ai/backend: localai
k8sgpts.k8sgpt.ai/name: k8sgpt-localai
k8sgpts.k8sgpt.ai/namespace: k8sgpt-operator-system
name: argocdargocdapplicationcontroller
namespace: k8sgpt-operator-system
resourceVersion: "8013179"
uid: b5411baf-cb92-4f37-82a1-fefbe2a0a942
spec:
backend: localai
details: |-
Error: StatefulSet uses a non-existent service argocd/argocd-application-controller.
Solution: 1. Check if the service name is correct. 2. Verify if the service is deployed. 3. Ensure the service is accessible within the cluster. 4. If the issue persists, recreate the StatefulSet with correct service details.
error:
- sensitive:
- masked: fCJqMndQ
unmasked: argocd
- masked: MVQ5Yl5vLTg7d0d5LDJmUHRjQjhmMXxeOVpOM0k=
unmasked: argocd-application-controller
text: StatefulSet uses the service argocd/argocd-application-controller which
does not exist.
kind: StatefulSet
name: argocd/argocd-application-controller
parentObject: ""
status:
lifecycle: historical
実際にリソースを見てみると StatefulSet は存在していますが、たしかに argocd-application-controller
という svc はありません。
代わりに svc argocd-applicationset-controller
が deployment argocd-applicationset-controller
に関連づいています。
$ k get statefulsets.apps
NAME READY AGE
argocd-application-controller 1/1 14d
$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.99.253.179 <none> 7000/TCP,8080/TCP 14d
argocd-dex-server ClusterIP 10.111.75.121 <none> 5556/TCP,5557/TCP,5558/TCP 14d
argocd-metrics ClusterIP 10.97.97.124 <none> 8082/TCP 14d
argocd-notifications-controller-metrics ClusterIP 10.111.78.10 <none> 9001/TCP 14d
argocd-redis ClusterIP 10.111.104.228 <none> 6379/TCP 14d
argocd-repo-server ClusterIP 10.96.70.22 <none> 8081/TCP,8084/TCP 14d
argocd-server ClusterIP 10.110.184.220 <none> 80/TCP,443/TCP 14d
argocd-server-metrics ClusterIP 10.102.135.119 <none> 8083/TCP 14d
$ k describe svc argocd-applicationset-controller
Name: argocd-applicationset-controller
Namespace: argocd
Labels: app.kubernetes.io/component=applicationset-controller
app.kubernetes.io/name=argocd-applicationset-controller
app.kubernetes.io/part-of=argocd
Annotations: <none>
Selector: app.kubernetes.io/name=argocd-applicationset-controller
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.99.253.179
IPs: 10.99.253.179
Port: webhook 7000/TCP
TargetPort: webhook/TCP
Endpoints: 10.244.1.20:7000
Port: metrics 8080/TCP
TargetPort: metrics/TCP
Endpoints: 10.244.1.20:8080
Session Affinity: None
Events: <none>
$ k get pod -o wide argocd-application-controller-0 argocd-applicationset-controller-8485455fd5-vhrj7
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
argocd-application-controller-0 1/1 Running 1 (4d1h ago) 13d 10.244.1.24 k8s-w1 <none> <none>
argocd-applicationset-controller-8485455fd5-vhrj7 1/1 Running 1 (4d1h ago) 14d 10.244.1.20 k8s-w1 <none> <none>
ただ上記リソースは argocd のインストール手順に沿ってデプロイされたものであり、そもそも pod 側からは関連付いているサービスを確認することができないのでどうやって StatefulSet が argocd-application-controller
を使用していることを検知したのかは疑問です。
生成 AI 系サービスでも内容が間違っていることはよくあることなので、上記の指摘もあまり妥当ではないと思われます。
Backend 関連の指摘では、svc backstage-front
の宛先 pod が設定されていないという内容になっています。
- apiVersion: core.k8sgpt.ai/v1alpha1
kind: Result
metadata:
creationTimestamp: "2024-08-11T10:25:45Z"
generation: 1
labels:
k8sgpts.k8sgpt.ai/backend: localai
k8sgpts.k8sgpt.ai/name: k8sgpt-localai
k8sgpts.k8sgpt.ai/namespace: k8sgpt-operator-system
name: backstagebackstagefront
namespace: k8sgpt-operator-system
resourceVersion: "8013181"
uid: b1d551d3-f078-4570-b82c-bc4ca92a57bb
spec:
backend: localai
details: |-
Error: The service with label app.kubernetes.io/name=backstage has no available endpoints.
Solution: Check the service and endpoint configuration, ensure the deployment is running, and verify the service is correctly associated with the desired endpoints. If needed, update or recreate the service and endpoints accordingly.
error:
- sensitive:
- masked: eVF1L3wsISNKUTBPVmJUWnkyLHN3fA==
unmasked: app.kubernetes.io/name
- masked: NmxoLDJ7UnRW
unmasked: backstage
text: Service has no endpoints, expected label app.kubernetes.io/name=backstage
kind: Service
name: backstage/backstage-front
parentObject: ""
status:
lifecycle: historical
リソースを見ると確かに Endpoints が設定されていないので、こちらは妥当な指摘であることが確認できます。
$ k describe svc backstage-front
Name: backstage-front
Namespace: backstage
Labels: <none>
Annotations: <none>
Selector: app.kubernetes.io/name=backstage
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.110.88.138
IPs: 10.110.88.138
Port: <unset> 80/TCP
TargetPort: 7007/TCP
Endpoints: <none>
Session Affinity: None
Events: <none>
実際に分析を行っているのは backend provider の AI サービス(ここでは LocalAI) なので分析内容はモデルによる要因も大きいかと思われますが、単にエラーとなっているリソースを検出するだけでなく上記のような設定に不備があるリソースなども検出できるようになっています。
k8sGPT の分析に対応しているリソースは Analyzer と呼ばれており、Github にサポートしている Analyze のリストがあります。
operator の architecture
かなり簡潔な図ですが operator の architecture は以下のようになっています。
operator のアーキテクチャ図。ドキュメント より引用
図中の K8sGPT deployment
が K8sGPT pod に対応しており、これが backend provider に指定した外部 LLM と通信してリソースの分析を行います。
そして k8sGPT operator
が K8sGPT pod と通信し、分析結果を元に result
カスタムリソースとして結果を公開するような仕組みになっています。
operator pod のログを見ると Creating new client for 10.108.64.236:8080
という行がありますが、これが通信対象の k8sGPT pod 内の k8sgpt コンテナの ip アドレスに対応しています。
k8sGPT pod の分析結果を元に argocdargocdapplicationcontroller
などの指摘項目を result として作成していることが確認できます。
また、一度 result が作成された後も Reconciling を実行し、指摘項目が解消されたかどうか定期的に確認しています。
2024-08-11T10:19:02Z INFO Starting workers {"controller": "k8sgpt", "controllerGroup": "core.k8sgpt.ai", "controllerKind": "K8sGPT", "worker count": 1}
Finished Reconciling k8sGPT
Finished Reconciling k8sGPT
Creating new client for 10.108.64.236:8080
Connection established between 10.108.64.236:8080 and localhost with time out of 1 seconds.
Remote Address : 10.108.64.236:8080
K8sGPT address: 10.108.64.236:8080
Created result argocdargocdapplicationcontroller
Created result backstagesamplenginxsvc
Created result backstagebackstagefront
Created result defaultbrokenpod
Finished Reconciling k8sGPT
Creating new client for 10.108.64.236:8080
Connection established between 10.108.64.236:8080 and localhost with time out of 1 seconds.
Remote Address : 10.108.64.236:8080
K8sGPT address: 10.108.64.236:8080
Checking if argocdargocdapplicationcontroller is still relevant
Checking if backstagesamplenginxsvc is still relevant
Checking if backstagebackstagefront is still relevant
Checking if defaultbrokenpod is still relevant
Finished Reconciling k8sGPT
指摘箇所を修正した場合は特に解消された等のログは出力されませんが、Checking if [resource] is still relevant
がなくなるので判断できます。
# defaultbrokenpod を修正したとき
Creating new client for 10.108.64.236:8080
Connection established between 10.108.64.236:8080 and localhost with time out of 1 seconds.
Remote Address : 10.108.64.236:8080
K8sGPT address: 10.108.64.236:8080
Checking if backstagebackstagefront is still relevant
Checking if argocdargocdapplicationcontroller is still relevant
Checking if backstagesamplenginxsvc is still relevant
Finished Reconciling k8sGPT
おわりに
k8sGPT は比較的歴史の浅いプロジェクトということもあって、ドキュメントがけっこう簡潔だったり設定項目がまだ少ないという面もありますが、近年の LLM ブームに相まって今後の機能拡張が期待されます。
コンセプトの一つに Codified SRE knowledge knows what to search for とあるように、知識や経験が必要となる k8s のトラブルシュートやトリアージ、脆弱性評価といった SRE に関連する作業を AI を使って実行できるというのが大きなメリットであると言えます。
ちなみに CNCF でのブログもあります。
Discussion