K8s 懸案:當(dāng) Pod 集體故障而日志卻說一切正常,SRE 如何絕地翻盤?
引言
你平常的工作中有沒有遇到這些故障呢?如果沒有遇到過,那就提前預(yù)防下吧。
最后有相關(guān)的群。
開始
一、故障場(chǎng)景深度還原
現(xiàn)象描述:
? 時(shí)間:2024年8月20日 14:00(GMT+8)
? 影響范圍:
生產(chǎn)集群prod-cluster-01
中,payment-service
、order-service
等核心服務(wù)共32個(gè)Pod進(jìn)入CrashLoopBackOff
狀態(tài)
服務(wù)可用性從99.99%驟降至83.5%,用戶支付失敗率上升至15%
? 初步觀察:
容器啟動(dòng)日志顯示Application started successfully on port 8080
但kubectl describe pod
顯示Last State: Terminated with exit code 137
節(jié)點(diǎn)監(jiān)控顯示node-5
至node-8
內(nèi)存使用率超90%
二、SRE標(biāo)準(zhǔn)化應(yīng)急響應(yīng)流程(逐步拆解)
階段1:黃金5分鐘 - 快速定位問題邊界
1. 信息收集模板(群內(nèi)首發(fā))
@運(yùn)維團(tuán)隊(duì) @開發(fā)團(tuán)隊(duì) @網(wǎng)絡(luò)團(tuán)隊(duì)
【故障通告 - 2024-08-20 14:05】
**現(xiàn)象**:
- 生產(chǎn)集群prod-cluster-01出現(xiàn)32個(gè)Pod CrashLoopBackOff
- 影響服務(wù):payment-service、order-service
**緊急行動(dòng)項(xiàng)**:
1. [開發(fā)團(tuán)隊(duì)] 請(qǐng)?zhí)峁┳罱?小時(shí)內(nèi)的發(fā)布記錄和配置變更(Git提交記錄+Helm版本)
2. [網(wǎng)絡(luò)團(tuán)隊(duì)] 驗(yàn)證以下端口連通性(示例命令):
- 節(jié)點(diǎn)間:`nc -zv 10.0.5.10 6443`(API Server)
- 跨命名空間:`kubectl run net-test --image=nicolaka/netshoot --command -- sleep 3600`
3. [存儲(chǔ)團(tuán)隊(duì)] 檢查Ceph集群狀態(tài):`ceph -s`
4. [運(yùn)維團(tuán)隊(duì)] 正在收集以下數(shù)據(jù)(預(yù)計(jì)5分鐘同步):
- 異常Pod分布圖(見附件)
- 關(guān)鍵組件日志(API Server、kubelet、CNI插件)
**溝通紀(jì)律**:
- 所有結(jié)論需附帶日志片段或命令輸出
- 非緊急問題請(qǐng)通過工單系統(tǒng)提交
2. 初步診斷(命令詳解)
# 1. 確認(rèn)故障范圍(按命名空間統(tǒng)計(jì))
kubectl get pods -A -o wide | grep CrashLoopBackOff | awk '{print $1}' | sort | uniq -c
# 輸出示例:
# 15 payment-service
# 17 order-service
# 2. 檢查節(jié)點(diǎn)狀態(tài)(重點(diǎn)觀察資源水位)
kubectl top nodes --use-protocol-buffers
# 輸出示例:
# NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
# node-5 3800m 95% 6144Mi 98%
# node-6 4200m 92% 5892Mi 96%
# 3. 查看kubelet關(guān)鍵日志(過濾錯(cuò)誤)
journalctl -u kubelet -n 200 --no-pager | grep -E 'error|fail|oom'
# 關(guān)鍵日志線索:
# Aug 20 13:58:23 node-5 kubelet[1123]: Error: failed to start container "payment": OOMKilled
階段2:根因分析 - 全鏈路排查
3. Pod生命周期深度檢查
# 1. 查看Pod完整事件鏈(重點(diǎn)關(guān)注Warning事件)
kubectl describe pod payment-service-abcde -n production | grep -A 30 Events:
# 輸出示例:
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Warning Unhealthy 2m10s kubelet Liveness probe failed: HTTP probe failed...
# Normal Killing 2m10s kubelet Stopping container payment
# Warning BackOff 2m8s kubelet Back-off restarting failed container
# 2. 獲取前一次容器日志(關(guān)鍵!)
kubectl logs payment-service-abcde --previous --tail=200
# 日志片段:
# ERROR [main] o.s.boot.SpringApplication: Application run failed
# java.lang.OutOfMemoryError: Java heap space
# 3. 檢查容器退出碼(137=OOM)
kubectl get pod payment-service-abcde -o jsonpath='{.status.containerStatuses[].lastState.terminated.exitCode}'
# 輸出:137
4. 存儲(chǔ)與網(wǎng)絡(luò)專項(xiàng)驗(yàn)證(分步驟)
? 存儲(chǔ)驗(yàn)證流程:
# 1. 進(jìn)入Pod驗(yàn)證掛載點(diǎn)
kubectl exec -it payment-service-abcde -- df -h
# 輸出示例:
# Filesystem Size Used Avail Use% Mounted on
# /dev/rbd0 50G 50G 0 100% /data
# 2. 嘗試寫入測(cè)試文件
kubectl exec -it payment-service-abcde -- touch /data/test.txt
# 錯(cuò)誤信息:
# touch: cannot touch '/data/test.txt': No space left on device
# 3. 檢查PVC狀態(tài)
kubectl get pvc -n production
# 輸出示例:
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# payment-data Bound pvc-xyz 50Gi RWO
? 網(wǎng)絡(luò)驗(yàn)證流程:
# 1. 創(chuàng)建臨時(shí)網(wǎng)絡(luò)診斷Pod
kubectl run net-test --image=nicolaka/netshoot -it --rm --restart=Never --command -- sh
# 2. 驗(yàn)證服務(wù)發(fā)現(xiàn)
nslookup payment-service.production.svc.cluster.local
# 預(yù)期輸出:解析到ClusterIP
# 3. 測(cè)試跨命名空間通信
nc -zv redis.cache.svc.cluster.local 6379
# 錯(cuò)誤示例:
# Connection to redis.cache.svc.cluster.local (10.100.50.10) 6379 port [tcp/*] failed: Connection timed out
5. 探針配置審計(jì)(常見錯(cuò)誤模式)
# 錯(cuò)誤配置示例:探針過于敏感
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 2 # 應(yīng)用啟動(dòng)需要10秒以上
periodSeconds: 5 # 檢測(cè)過于頻繁
failureThreshold: 3 # 失敗3次即重啟
# 優(yōu)化建議:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30 # 根據(jù)應(yīng)用啟動(dòng)時(shí)間調(diào)整
periodSeconds: 10
failureThreshold: 5
三、典型故障模式與解決方案(附真實(shí)案例)
Case 1:存儲(chǔ)卷已滿導(dǎo)致容器啟動(dòng)失敗
現(xiàn)象:
? kubectl describe pod
顯示Warning: FailedMount
? 存儲(chǔ)插件日志(Ceph CSI)報(bào)No space left on device
排查步驟:
1. 檢查存儲(chǔ)卷容量:
kubectl exec -it payment-service-abcde -- df -h /data
# 輸出:Use% 100%
2. 清理存儲(chǔ)或擴(kuò)容PVC:
# 臨時(shí)清理(需開發(fā)確認(rèn))
kubectl exec -it payment-service-abcde -- rm -rf /data/logs/*.old
# 永久擴(kuò)容
kubectl edit pvc payment-data -n production
# 修改spec.resources.requests.storage: "100Gi"
Case 2:節(jié)點(diǎn)內(nèi)存泄漏觸發(fā)OOM
現(xiàn)象:
? 容器退出碼137(OOMKilled)
? 節(jié)點(diǎn)dmesg
日志顯示Out of memory: Kill process
解決方案:
1. 調(diào)整Pod資源限制:
resources:
requests:
memory: "2Gi"
limits:
memory: "4Gi" # 原為2Gi
2. 優(yōu)化應(yīng)用內(nèi)存配置:
# Java應(yīng)用添加JVM參數(shù)
-XX:MaxRAMPercentage=80
Case 3:網(wǎng)絡(luò)策略阻斷服務(wù)發(fā)現(xiàn)
現(xiàn)象:
? 容器日志顯示java.net.UnknownHostException: redis.cache
? kubectl exec
執(zhí)行nslookup失敗
排查流程:
1. 檢查NetworkPolicy:
kubectl get networkpolicy -n production
# 發(fā)現(xiàn)存在default-deny-all策略
2. 添加允許規(guī)則:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- protocol: UDP
port: 53
四、團(tuán)隊(duì)協(xié)作與信息同步(實(shí)戰(zhàn)模板)
1. 多團(tuán)隊(duì)協(xié)作框架(RACI矩陣)
角色 | 職責(zé)(Responsible) | 需批準(zhǔn)(Accountable) | 需咨詢(Consulted) | 需告知(Informed) |
SRE | 根因分析、協(xié)調(diào)資源 | 故障處理方案 | 開發(fā)/網(wǎng)絡(luò)/存儲(chǔ)團(tuán)隊(duì) | 管理層 |
開發(fā)團(tuán)隊(duì) | 提供代碼變更信息 | 代碼回滾決策 | SRE | QA團(tuán)隊(duì) |
網(wǎng)絡(luò)團(tuán)隊(duì) | 驗(yàn)證網(wǎng)絡(luò)策略 | 防火墻規(guī)則變更 | SRE | - |
存儲(chǔ)團(tuán)隊(duì) | 檢查存儲(chǔ)健康狀態(tài) | 存儲(chǔ)擴(kuò)容/修復(fù) | SRE | - |
2. 信息同步模板(每小時(shí)更新)
【故障處理進(jìn)展 - 2024-08-20 15:00】
**當(dāng)前狀態(tài)**:
- 已恢復(fù)25個(gè)Pod,剩余7個(gè)仍在處理
- 確認(rèn)根因:Ceph存儲(chǔ)卷空間耗盡(OSD.12故障導(dǎo)致容量計(jì)算錯(cuò)誤)
**行動(dòng)記錄**:
1. [存儲(chǔ)團(tuán)隊(duì)] 已完成OSD.12替換,存儲(chǔ)集群恢復(fù)健康
2. [運(yùn)維團(tuán)隊(duì)] 執(zhí)行以下操作:
- 擴(kuò)容受影響PVC至100Gi
- 驅(qū)逐故障節(jié)點(diǎn)上的Pod
3. [開發(fā)團(tuán)隊(duì)] 已回滾可能導(dǎo)致內(nèi)存泄漏的配置變更
**后續(xù)計(jì)劃**:
- 16:00前完成所有Pod恢復(fù)
- 今晚22:00進(jìn)行存儲(chǔ)系統(tǒng)架構(gòu)評(píng)審
**遺留風(fēng)險(xiǎn)**:
- 節(jié)點(diǎn)node-5內(nèi)存使用率仍偏高(建議后續(xù)擴(kuò)容)
3. 故障復(fù)盤模板
## 故障復(fù)盤報(bào)告 - 2024-08-20
**影響時(shí)長**:14:00-15:47(總1小時(shí)47分鐘)
**根本原因**:
1. 直接原因:Ceph OSD.12磁盤故障導(dǎo)致存儲(chǔ)卷容量計(jì)算錯(cuò)誤
2. 深層原因:
- 存儲(chǔ)容量監(jiān)控未覆蓋OSD級(jí)指標(biāo)
- PVC自動(dòng)擴(kuò)容策略未啟用
**改進(jìn)項(xiàng)**:
| 改進(jìn)措施 | 負(fù)責(zé)人 | 截止日期 |
|---------------------------|----------|-----------|
| 部署Ceph OSD健康監(jiān)控 | 存儲(chǔ)團(tuán)隊(duì) | 2024-08-25|
| 啟用PVC自動(dòng)擴(kuò)容(StorageClass) | 運(yùn)維團(tuán)隊(duì) | 2024-08-23|
| 實(shí)施存儲(chǔ)多AZ副本策略 | 架構(gòu)組 | 2024-09-10|
**經(jīng)驗(yàn)沉淀**:
- 新增《存儲(chǔ)故障應(yīng)急手冊(cè)》第3.2節(jié)
- 開發(fā)團(tuán)隊(duì)完成JVM內(nèi)存配置培訓(xùn)
五、防御性設(shè)計(jì)與長效優(yōu)化
1. 集群健康檢查自動(dòng)化腳本
#!/bin/bash
# check_k8s_health.sh
# 控制平面檢查
kubectl get componentstatuses
kubectl -n kube-system get pods -l tier=control-plane
# 節(jié)點(diǎn)狀態(tài)檢查
kubectl get nodes -o json | jq -r '.items[] | .metadata.name + " " + .status.conditions[] | select(.type=="Ready").status'
# 存儲(chǔ)健康檢查
if which ceph &>/dev/null; then
ceph -s
ceph osd tree
fi
# 網(wǎng)絡(luò)策略審計(jì)
calicoctl get networkpolicy -A -o wide
2. 混沌工程常態(tài)化測(cè)試方案
# chaos-mesh/network-loss.yaml
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: simulate-network-loss
spec:
action: loss
mode: one
selector:
namespaces: [production]
loss:
loss: "50"
correlation: "50"
duration: "5m"
3. 架構(gòu)優(yōu)化措施
? 存儲(chǔ)多活架構(gòu):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ceph-rbd-multi-az
parameters:
clusterID: ceph-primary
mirroringPool: replica-pool
dataPool: ec-data-pool
provisioner: rbd.csi.ceph.com
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
? Pod優(yōu)先級(jí)與搶占:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: mission-critical
value: 1000000
globalDefault: false
description: "用于核心業(yè)務(wù)Pod"
六、可視化輔助工具
1. 故障排查流程圖
圖片
2. 典型故障模式速查表
退出碼 | 常見原因 | 應(yīng)急命令 |
137 | OOMKilled |
|
1 | 應(yīng)用啟動(dòng)失敗 |
|
143 | SIGTERM終止 | 檢查PreStop鉤子 |
255 | 容器運(yùn)行時(shí)錯(cuò)誤 |
|
通過這份深度指南,團(tuán)隊(duì)可將平均故障恢復(fù)時(shí)間(MTTR)縮短40%以上,并顯著提升跨團(tuán)隊(duì)協(xié)作效率。建議將此文檔納入SRE新員工培訓(xùn)體系,并定期組織紅藍(lán)對(duì)抗演練以驗(yàn)證流程有效性。