AIOps系列 | 開發(fā) K8s GPT 故障診斷工具
前面我們介紹了 《開發(fā) K8s Chat 命令行工具》,實(shí)現(xiàn)了通過和 Kubernetes 進(jìn)行交互的方式進(jìn)行運(yùn)維,雖然文章中所描述的功能比較簡單,但是可以以此進(jìn)行擴(kuò)展,豐富功能。
那本章,我們將在 《開發(fā) K8s Chat 命令行工具》的基礎(chǔ)之上,增加 Kubernetes 故障診斷工具,其主要功能點(diǎn)是:
- 獲取集群的 event 時(shí)間,特別關(guān)注 warning 級別事件
- 然后進(jìn)入對應(yīng)的 pod 獲取日志
- 大模型結(jié)合事件和日志進(jìn)行分析,得出解決問題的建議
當(dāng)然,這里也只是起到一個(gè)拋磚引玉的作用,提供簡單的思路,可以自行擴(kuò)展。
開發(fā)過程
(1)首先使用 cobra-cli 新增一個(gè) analyze 命令
cobra-cli add analyze(2)然后在 analyze 下面添加一個(gè)子命令 event,專門用于分析事件
cobra-cli add event -p 'analyzeCmd'(3)設(shè)計(jì)一個(gè)方法 getPodEventsAndLogs 用于獲取 K8s 的事件和日志
// int64Ptr 輔助函數(shù),用于創(chuàng)建 int64 指針
func int64Ptr(i int64) *int64 {
return &i
}
func getPodEventsAndLogs() (map[string][]string, error) {
// 創(chuàng)建 Kubernetes 客戶端
clientGo, err := utils.NewClientGo(kubeconfig)
if err != nil {
return nil, fmt.Errorf("創(chuàng)建 Kubernetes 客戶端失敗: %v", err)
}
// 存儲每個(gè) Pod 的事件和日志信息
result := make(map[string][]string)
processedPods := make(map[string]bool) // 避免重復(fù)處理同一個(gè) Pod
// 獲取 Warning 級別的事件
events, err := clientGo.Clientset.CoreV1().Events("").List(context.TODO(), metav1.ListOptions{
FieldSelector: "type=Warning",
})
if err != nil {
return nil, fmt.Errorf("獲取事件失敗: %v", err)
}
for _, event := range events.Items {
// 只處理 Pod 相關(guān)的事件
if event.InvolvedObject.Kind != "Pod" {
continue
}
podName := event.InvolvedObject.Name
namespace := event.InvolvedObject.Namespace
message := event.Message
podKey := fmt.Sprintf("%s/%s", namespace, podName)
// 避免重復(fù)處理同一個(gè) Pod
if processedPods[podKey] {
// 如果已經(jīng)處理過這個(gè) Pod,只添加新的事件信息
result[podKey] = append(result[podKey], fmt.Sprintf("Additional Event: %s", message))
continue
}
// 標(biāo)記為已處理
processedPods[podKey] = true
// 獲取 Pod 日志(添加限制和更好的錯(cuò)誤處理)
logOptions := &corev1.PodLogOptions{
TailLines: int64Ptr(100), // 限制日志行數(shù)為最后100行
LimitBytes: int64Ptr(1024 * 1024), // 限制日志大小為1MB
}
req := clientGo.Clientset.CoreV1().Pods(namespace).GetLogs(podName, logOptions)
podLogs, err := req.Stream(context.TODO())
if err != nil {
// 即使獲取日志失敗,也保存事件信息
result[podKey] = append(result[podKey], fmt.Sprintf("Event Message: %s", message))
result[podKey] = append(result[podKey], fmt.Sprintf("Namespace: %s", namespace))
result[podKey] = append(result[podKey], fmt.Sprintf("日志獲取失敗: %v", err))
continue
}
// 使用匿名函數(shù)確保資源及時(shí)釋放
func() {
defer podLogs.Close()
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(podLogs)
if err != nil {
// 日志讀取失敗,但仍保存事件信息
result[podKey] = append(result[podKey], fmt.Sprintf("Event Message: %s", message))
result[podKey] = append(result[podKey], fmt.Sprintf("Namespace: %s", namespace))
result[podKey] = append(result[podKey], fmt.Sprintf("日志讀取失敗: %v", err))
return
}
// 成功獲取日志,保存完整信息
result[podKey] = append(result[podKey], fmt.Sprintf("Event Message: %s", message))
result[podKey] = append(result[podKey], fmt.Sprintf("Namespace: %s", namespace))
result[podKey] = append(result[podKey], fmt.Sprintf("Logs:\n%s", buf.String()))
}()
}
return result, nil
}我們使用一個(gè) map[string][]string 來保存 pod 的事件和日志信息,然后通過 client-go 獲取 warning 級別的事件,最后過濾需要的 pod 事件以及 pod 相關(guān)信息,然后繼續(xù)通過 client-go 獲取對應(yīng) pod 的日志,然后把這些信息放到 map 中。
(4)設(shè)計(jì)一個(gè) sendToChatGPT 的方法,接受 pod 的事件和日志信息,然后通過 AI 對其進(jìn)行分析
// sendToChatGPT 函數(shù)接受 podInfo map,發(fā)送給 OpenAI 的 ChatGPT 獲取診斷建議
func sendToChatGPT(podInfo map[string][]string) (string, error) {
// 檢查輸入數(shù)據(jù)
if len(podInfo) == 0 {
return "未發(fā)現(xiàn)任何 Pod Warning 事件", nil
}
// 創(chuàng)建 OpenAI 客戶端
client, err := utils.NewOpenAIClient()
if err != nil {
return "", fmt.Errorf("創(chuàng)建 OpenAI 客戶端失敗: %v", err)
}
// 構(gòu)建結(jié)構(gòu)化的信息字符串
combinedInfo := buildPodInfoString(podInfo)
// 輸出調(diào)試信息(可選,生產(chǎn)環(huán)境可移除)
fmt.Printf("正在分析 %d 個(gè) Pod 的問題...\n", len(podInfo))
fmt.Println("詳細(xì)信息:")
fmt.Println(combinedInfo)
fmt.Println("正在請求 AI 分析...")
// 構(gòu)造優(yōu)化的 ChatGPT 請求消息
messages := []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Content: `您是一位資深的 Kubernetes 專家和故障診斷專家。您的任務(wù)是:
1. 分析 Pod 的 Warning 事件和日志
2. 識別根本原因
3. 提供具體的、可操作的解決方案
4. 優(yōu)先推薦命令行解決方案,必要時(shí)提供 YAML 配置
5. 按問題嚴(yán)重程度排序建議`,
},
{
Role: openai.ChatMessageRoleUser,
Content: fmt.Sprintf(`請分析以下 Kubernetes Pod 問題:
%s
請?zhí)峁?1. 問題根本原因分析
2. 具體解決步驟(優(yōu)先使用 kubectl 命令)
3. 預(yù)防措施建議
4. 如果需要 YAML 配置,請?zhí)峁┩暾纠?
請確保建議具體可操作,避免泛泛而談。`, combinedInfo),
},
}
// 請求 ChatGPT 獲取建議
resp, err := client.Client.CreateChatCompletion(
context.TODO(),
openai.ChatCompletionRequest{
Model: openai.GPT4oMini,
Messages: messages,
MaxTokens: 2000, // 限制響應(yīng)長度
Temperature: 0.1, // 降低隨機(jī)性,提高一致性
},
)
if err != nil {
return "", fmt.Errorf("調(diào)用 OpenAI API 失敗: %v", err)
}
// 驗(yàn)證響應(yīng)
if len(resp.Choices) == 0 {
return "", fmt.Errorf("OpenAI 返回空響應(yīng)")
}
responseText := resp.Choices[0].Message.Content
if responseText == "" {
return "AI 分析完成,但未返回具體建議", nil
}
return responseText, nil
}
// buildPodInfoString 構(gòu)建格式化的 Pod 信息字符串
func buildPodInfoString(podInfo map[string][]string) string {
var builder strings.Builder
builder.WriteString("發(fā)現(xiàn)以下 Pod Warning 事件及其日志:\n\n")
podCount := 0
for podKey, info := range podInfo {
podCount++
builder.WriteString(fmt.Sprintf("=== Pod %d: %s ===\n", podCount, podKey))
// 分類顯示信息
for _, line := range info {
if strings.HasPrefix(line, "Event Message:") {
builder.WriteString(fmt.Sprintf("?? %s\n", line))
} else if strings.HasPrefix(line, "Namespace:") {
builder.WriteString(fmt.Sprintf("?? %s\n", line))
} else if strings.HasPrefix(line, "Logs:") {
builder.WriteString(fmt.Sprintf("?? %s\n", line))
} else if strings.HasPrefix(line, "Additional Event:") {
builder.WriteString(fmt.Sprintf("?? %s\n", line))
} else {
builder.WriteString(fmt.Sprintf("%s\n", line))
}
}
builder.WriteString("\n")
}
return builder.String()
}和 AI 的對話主要就是 prompt 的設(shè)計(jì),然后把具體的參數(shù)傳進(jìn)去即可,沒有特別的地方。
(5)使用 k8scopilot.exe analyze event 進(jìn)行分析驗(yàn)證
分析結(jié)果如下:
正在請求 AI 分析...
根據(jù)您提供的 Kubernetes Pod 日志和事件信息,以下是對問題的根本原因分析、解決步驟、預(yù)防措施建議以及必要的 YAML 配置示例。
### 1. 問題根本原因分析
- **資源不足**:
- 多個(gè) Pod 報(bào)告了 `ephemeral-storage` 不足的問題,導(dǎo)致 Pod 無法正常運(yùn)行或重啟。
- 許多 Pod 由于節(jié)點(diǎn)的 `DiskPressure` 狀態(tài)而無法調(diào)度或運(yùn)行。
- **網(wǎng)絡(luò)連接問題**:
- 多個(gè) Pod 的就緒探針和存活探針失敗,顯示連接超時(shí)或連接被拒絕,表明服務(wù)未能在指定端口上啟動。
- **依賴注入失敗**:
- 一些 Pod 報(bào)告了 Spring Boot 應(yīng)用程序的依賴注入失敗,特別是與 Dubbo 相關(guān)的服務(wù)未能正確配置。
- **鏡像拉取失敗**:
- 一些 Pod 報(bào)告了 `ImagePullBackOff`,這通常是由于鏡像不存在或訪問權(quán)限問題。
### 2. 具體解決步驟
#### 2.1 解決資源不足問題
- **清理節(jié)點(diǎn)上的不必要的資源**:
kubectl delete pod --all -n kube-system
kubectl delete pod --all -n log
- **增加節(jié)點(diǎn)的存儲資源**:
如果可能,增加節(jié)點(diǎn)的存儲容量,或者添加新的節(jié)點(diǎn)。
- **調(diào)整 Pod 的資源請求和限制**:
確保 Pod 的 `ephemeral-storage` 請求和限制設(shè)置合理??梢酝ㄟ^以下命令編輯 Pod 的 YAML 配置:
```bash
kubectl edit deployment <deployment-name> -n <namespace>
在容器部分添加:
resources:
requests:
ephemeral-storage: "100Mi"
limits:
ephemeral-storage: "200Mi"
#### 2.2 解決網(wǎng)絡(luò)連接問題
- **檢查服務(wù)是否正常運(yùn)行**:
確保 Pod 中的服務(wù)在預(yù)期的端口上啟動??梢酝ㄟ^以下命令查看 Pod 的狀態(tài):
```bash
kubectl get pods -n <namespace>
- **查看 Pod 日志**:
kubectl logs <pod-name> -n <namespace>
- **增加探針的超時(shí)時(shí)間**:
如果服務(wù)啟動較慢,可以增加就緒探針和存活探針的超時(shí)時(shí)間:
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
#### 2.3 解決依賴注入失敗
- **檢查 Dubbo 配置**:
確保 Dubbo 的注冊中心配置正確??梢栽趹?yīng)用的配置文件中添加:
dubbo:
registry:
address: "zookeeper://localhost:2181"
- **重啟相關(guān) Pod**:
```bash
kubectl rollout restart deployment <deployment-name> -n <namespace>
#### 2.4 解決鏡像拉取失敗
- **檢查鏡像是否存在**:
確保指定的鏡像在容器注冊中心中存在,并且訪問權(quán)限正確。
- **更新鏡像標(biāo)簽**:
如果鏡像標(biāo)簽不正確,可以更新為正確的標(biāo)簽:
kubectl set image deployment/<deployment-name> <container-name>=<new-image>:<tag> -n <namespace>
### 3. 預(yù)防措施建議
- **監(jiān)控資源使用情況**:
使用 Kubernetes 的監(jiān)控工具(如 Prometheus 和 Grafana)監(jiān)控節(jié)點(diǎn)和 Pod 的資源使用情況,及時(shí)發(fā)現(xiàn)并解決資源不足的問題。
- **設(shè)置合理的資源請求和限制**:
在 Pod 的 YAML 配置中設(shè)置合理的資源請求和限制,以避免資源爭用。
- **定期清理不必要的資源**:
定期檢查和清理不再使用的 Pod 和鏡像,以釋放存儲空間。從上面的分析結(jié)果可以看到基本能夠給出比較準(zhǔn)確的建議。
當(dāng)然,這里只是診斷問題,還可以對其功能進(jìn)行擴(kuò)展,比如:
- 故障自愈:
- 結(jié)合 Function Calling 實(shí)現(xiàn)自動修復(fù)簡單問題
- 增強(qiáng)分析:
- 增加更多診斷數(shù)據(jù)源(metrics、節(jié)點(diǎn)狀態(tài)等)
- 實(shí)現(xiàn)歷史問題匹配和知識庫
- 可視化:
- 生成 HTML 格式的診斷報(bào)告
- 支持問題嚴(yán)重程度分級展示
最后
本文在《開發(fā) K8s Chat 命令行工具》的基礎(chǔ)上,進(jìn)一步實(shí)現(xiàn)了 Kubernetes 故障診斷功能,核心思路是通過工具獲取集群中 Warning 級別的事件及對應(yīng) Pod 的日志,再借助大模型分析并輸出解決方案,為運(yùn)維工作提供了便捷的故障排查途徑。
具體而言,開發(fā)過程通過 cobra-cli 新增 analyze 命令及子命令 event,構(gòu)建 getPodEventsAndLogs 方法獲取相關(guān)事件與日志,設(shè)計(jì) sendToChatGPT 方法將信息傳入大模型進(jìn)行分析。





















