引言
无论Kubernetes多么流行,它仍可能让最资深的 DevOps 工程师感到棘手。尽管它在大规模处理容器化应用方面表现出色,但也带来了独特的故障排除挑战。本文翻译总结来middleware官网,探讨每位DevOps工程师都应掌握的十大Kubernetes故障排除技巧,这些技巧源自实际场景,可帮助快速、可靠地解决常见及关键问题。
https://middleware.io/blog/kubernetes-troubleshooting-techniques
本文包含哪些内容
1.修复 Pod 中的 CrashLoopBackOff 错误2.Kubernetes 故障排除:部署失败之 ImagePullBackOff3.Kubernetes 故障排除:修复节点未就绪(NotReady)错误4.诊断服务和网络问题:Pending 错误5.Kubernetes 高资源使用率故障排除:解决 OOMKilled 错误6.Kubernetes 存储故障排除:解决 PVC 挂起(Pending)错误7.使用事件和审计日志:深入系统分析8.使用 Kubernetes Dashboard 及可视化工具9.实现健康检查和探针(Probe)10.高级调试技术使用:Middleware 等监控和追踪工具
1.修复Pod中的CrashLoopBackOff错误
CrashLoopBackOff 是 Kubernetes 中最常见且令人沮丧的问题之一:Pod 在重启过程中反复崩溃,原因是容器无法正确启动,Kubernetes 持续尝试重启导致失败循环。
步骤1:列出所有Pod
首先通过以下命令了解命名空间中所有 Pod 的状态,定位异常 Pod:
kubectl get pods
输出会显示每个Pod的状态、重启次数和运行时长,状态为 CrashLoopBackOff
的 Pod 需优先处理。
步骤2:描述受影响的Pod
确定问题 Pod 后,使用 describe
命令查看其内部细节(配置、近期事件、错误信息):
kubectl describe pod <pod-name>
重点关注 Events(事件) 部分,可定位镜像拉取失败、配置缺失、权限错误等问题。
步骤3:查看容器日志
日志是理解容器内部故障的关键,若 Pod 崩溃前未生成日志,可通过 --previous
查看上一次失败实例的日志:
kubectl logs <pod-name> --previous
示例场景
- 运行
kubectl get pods
发现异常:
my-webapp-pod 0/1 CrashLoopBackOff 5 (2m ago)
- 查看上一次失败日志:
kubectl logs my-webapp-pod --previous
# 输出:Error: DATABASE_URL environment variable is not set; Process exiting with code 1
- 根因:容器缺少
DATABASE_URL
环境变量,补充配置后即可修复。
2.Kubernetes故障排除部署失败之ImagePullBackOff
当 Kubernetes 因认证问题或镜像名称错误无法拉取容器镜像时,会触发 ImagePullBackOff
错误。
步骤 1:识别有问题的部署
先通过以下命令检查部署状态,重点关注 READY(就绪) 列(如“0/3”表示无 Pod 成功启动):
kubectl get deployments
如需更详细信息(Pod 模板、事件),运行:
kubectl describe deployment <deployment-name>
步骤2:监控部署状态和历史
- 实时跟踪部署进度:
kubectl rollout status deployment <deployment-name>
- 查看部署历史(定位哪个版本引入问题):
kubectl rollout history deployment <deployment-name>
步骤3:调查ImagePullBackOff根因
- 列出Pod并确认错误状态:
kubectl get pods
# 输出:my-app-7d4b8c8f-xyz 0/1 ImagePullBackOff 0 2m
- 描述Pod查看具体错误:
kubectl describe pod my-app-7d4b8c8f-xyz
# 输出:Failed to pull image "private-registry.com/my-app:v1.2.3": pull access denied
根因:私有镜像仓库认证失败。
步骤4:使用Secret修复ImagePullBackOff
- 创建存储私有仓库凭据的Secret:
kubectl create secret docker-registry my-registry-secret \
--docker-server=private-registry.com \
--docker-username=<your-username> \
--docker-password=<your-password> \
--docker-email=<your-email>
- 更新部署以引用该Secret:
kubectl patch deployment my-app -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"my-registry-secret"}]}}}}'
- 监控修复后的部署:
kubectl rollout status deployment my-app
3.Kubernetes故障排除修复节点未就绪(NotReady)错误
节点出现 NotReady
状态会阻碍 Pod 调度、干扰工作负载,通常原因是 kubelet 与服务器通信失败 或 节点健康检查未通过。
步骤1:检查节点状态
通过以下命令查看所有节点的状态、容器运行时、IP 等信息:
kubectl get nodes -o wide
-o wide
可显示额外上下文(如 OS 版本、子网信息),帮助定位节点级问题。
步骤2:检查节点资源和健康状态
查看节点的资源容量(CPU、内存)和健康条件,识别资源过载问题:
kubectl describe node <node-name> | grep -A 5 "Capacity\|Allocatable"
步骤3:示例:修复磁盘压力(DiskPressure)问题
- 发现节点
worker-node-1
状态为NotReady
:
kubectl get nodes
# 输出:worker-node-1 NotReady 5d v1.28.0
- 描述节点查看根因:
kubectl describe node worker-node-1
# 输出:Conditions: DiskPressure True (KubeletHasDiskPressure: kubelet has disk pressure)
- 清理系统日志释放磁盘空间:
sudo journalctl --vacuum-time=3d # 删除 3 天前的日志
清理后,kubelet 会自动将节点恢复为 Ready
状态。
4.诊断服务和网络问题Pending错误
Pod 或服务卡在 Pending
状态通常源于 标签选择器不匹配、网络配置错误 或 DNS 解析失败。
步骤1:验证服务配置
- 列出所有服务,查看网络详情(IP、端口):
kubectl get services --all-namespaces
- 检查服务的Endpoint(若为空,说明无 Pod 匹配服务的选择器):
kubectl get endpoints <service-name>
- 描述服务,确认选择器标签与 Pod 标签一致:
kubectl describe service <service-name>
步骤2:检查集群DNS问题
若微服务间通信失败,需验证 DNS 解析:
- 在 od内部运行
nslookup
测试服务解析:
kubectl exec -it <pod-name> -- nslookup <service-name>
kubectl exec -it <pod-name> -- nslookup <service-name>.<namespace>.svc.cluster.local
若无法解析到IP,说明集群 DNS 配置异常。
- 测试HTTP连通性:
kubectl exec -it <pod-name> -- wget -qO- <service-name>:<port>/health
若请求失败,需检查服务配置、网络策略或选择器匹配问题。
5. Kubernetes高资源使用率故障排除解决OOMKilled错误
当容器超出分配的内存限制时,Kubernetes 会强制终止容器,触发 OOMKilled
错误,可能导致 Pod 驱逐、应用 downtime。
步骤1:检查资源使用率
- 查看节点级资源使用情况(识别高内存节点):
kubectl top nodes
内存使用率超过 80% 的节点易触发 OOMKilled 错误。
- 查看 Pod 级资源使用,按 CPU/内存排序:
kubectl top pods --all-namespaces --sort-by=cpu
kubectl top pods --all-namespaces --sort-by=memory
步骤2:检查资源配额和自动扩缩容
- 查看所有命名空间的资源配额:
kubectl describe quota --all-namespaces
- 监控 Pod 实时内存消耗(每 5 秒刷新,识别内存泄漏):
watch -n 5 'kubectl top pod <pod-name>'
步骤3:检查Pod资源请求和限制
查看 Pod 是否配置了合理的内存限制(无限制可能导致资源滥用):
kubectl describe pod <pod-name> | grep -A 10 "Requests\|Limits"
步骤4:缓解资源问题
通过 Horizontal Pod Autoscaling(HPA) 自动扩缩容,避免资源过载:
- 基于CPU使用率(70%)配置HPA:
kubectl autoscale deployment <deployment-name> --cpu-percent=70 --min=2 --max=10
- 验证HPA状态:
kubectl get hpa
kubectl describe hpa <deployment-name>
6.Kubernetes存储故障排除解决PVC挂起(Pending)错误
PersistentVolumeClaim(PVC)处于 Pending
状态意味着应用无法访问持久化数据,通常原因是 存储类配置错误、卷供应器缺失 或 集群存储不足。
步骤1:检查PV和PVC状态
列出所有 PersistentVolume(PV)和 PVC,查看其 状态(是否绑定)、访问模式 和 容量:
kubectl get pv,pvc --all-namespaces
步骤2:排查PVC挂起原因
描述 PVC,重点关注 Events 部分,定位根因(如无匹配 PV、存储类不存在):
kubectl describe pvc <pvc-name>
步骤3:验证存储类
- 列出所有可用存储类:
kubectl get storageclass
- 描述存储类,确认供应器和参数配置正确:
kubectl describe storageclass <storageclass-name>
步骤4:示例:修复存储类不匹配问题
- 描述 PVC 发现错误:
kubectl describe pvc my-data-pvc
# 输出:Warning ProvisioningFailed storageclass.storage.k8s.io "fast-ssd" not found
- 确认可用存储类:
kubectl get storageclass
# 输出:standard (default), gp2
- 更新PVC,引用存在的存储类(如
gp2
),问题解决。
7.使用事件和审计日志:深入系统分析
Kubernetes 事件和审计日志是调试的核心工具,可追踪“发生了什么、何时发生、为何发生”,为根因分析提供时间线。
步骤1:使用Kubernetes事件
事件记录集群内部活动,可按时间排序、过滤警告类型或实时监控:
- 按时间排序查看所有事件(最新事件在末尾):
kubectl get events --all-namespaces --sort-by='.metadata.creationTimestamp'
- 过滤特定时间后的事件:
kubectl get events --field-selector='lastTimestamp>2023-10-01T10:00:00Z'
- 仅查看警告事件:
kubectl get events --field-selector type=Warning
- 实时监控事件:
kubectl get events --watch
- 过滤特定 Pod/服务的事件:
kubectl get events --field-selector involvedObject.name=<pod-name>
- 定位Pod调度失败原因:
kubectl get events --field-selector reason=FailedScheduling
步骤2:使用审计日志进行深度排查
审计日志记录 API 层面的“谁做了什么”,适用于安全调查或追踪管理员操作(默认未启用,需配置审计策略)。
示例审计策略配置
apiVersion: audit.k8s.io/v1
kind:Policy
rules:
-level:RequestResponse# 记录请求和响应详情
resources:
-group:""
resources:["pods","services"]
-group:"apps"
resources:["deployments","replicasets"]
-level:Request# 仅记录请求
resources:
-group:""
resources:["configmaps","secrets"]
审计日志示例(关键信息)
{
"auditID": "4d2c8b7a-f3e1-4b2a-9c8d-1e3f5a7b9c2d",
"verb": "delete", # 操作类型
"user": {"username": "admin@company.com"}, # 操作人
"sourceIPs": ["192.168.1.100"], # 来源 IP
"objectRef": {"resource": "pods", "name": "web-app-7d4b8c9f-xyz"}, # 目标资源
"responseStatus": {"code": 200} # 操作结果
}
8. 使用Kubernetes Dashboard及可视化工具
kubectl
等命令行工具功能强大,但可视化工具(如 Kubernetes Dashboard、Middleware)可简化集群管理,直观展示指标、日志和事件的关联模式。
步骤1:部署和使用Kubernetes Dashboard
Kubernetes Dashboard 是基于 Web 的 UI,默认未安装(出于安全考虑),部署步骤如下:
- 部署 Dashboard:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
- 创建管理员服务账户:
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
- 生成访问令牌:
kubectl create token dashboard-admin -n kubernetes-dashboard
- 访问Dashboard:
- 运行
kubectl proxy
,通过浏览器访问:http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
- 输入步骤 3 生成的令牌登录。
- 运行
Dashboard核心功能
- 实时监控 CPU/内存使用率趋势
- 可视化事件时间线
- 查看资源间依赖关系
- 浏览器内流式查看应用日志·
步骤2:使用Middleware等第三方可视化工具
Kubernetes Dashboard 缺乏完整的可观测性,Middleware 等工具可整合 指标、日志、追踪和告警,提供统一视图。
部署MiddlewareAgent(DaemonSet 方式)
apiVersion: apps/v1
kind:DaemonSet
metadata:
name:middleware-agent
namespace:middleware
spec:
selector:
matchLabels:
app:middleware-agent
template:
metadata:
labels:
app:middleware-agent
spec:
containers:
-name:middleware-agent
image:middleware/agent:latest
env:
-name:MW_API_KEY
valueFrom:
secretKeyRef:
name:middleware-secret
key:api-key
-name:MW_TARGET
集成后,你可以可视化你的容器组,从各种来源收集指标,还能监控部署状态。
9. 实施健康检查和探针
Kubernetes 中的健康检查类似常规体检,可帮助及早发现问题并确保所有组件按预期运行。Kubernetes 通过探针(Probes) 监控应用容器的健康状态与可用性,当检测到异常时,集群能自动执行重启容器、停止流量路由等操作,避免故障扩散。
9.1 了解就绪探针和存活探针
Kubernetes 提供三种探针,每种探针在维护容器健康中承担特定角色,需根据应用场景组合使用:
探针类型(Probe Type) | 核心作用 | 触发动作 | 适用场景 |
---|---|---|---|
存活探针(Liveness Probe) | 检查容器是否“存活”(正常运行) | 连续失败时,自动重启容器 | 应用死锁、进程挂起等无法自我恢复的场景 |
就绪探针(Readiness Probe) | 检查容器是否“就绪”(可接收流量) | 失败时,将容器从服务端点移除 | 应用启动中(如加载配置、初始化数据库)、临时依赖不可用(如缓存宕机)的场景 |
启动探针(Startup Probe) | 为启动慢的应用提供额外初始化时间 | 失败时,重启容器;成功后,激活其他探针 | 大型应用、数据库(如 MySQL、Elasticsearch)等启动耗时超过默认阈值的场景 |
9.2 Example: Configuring All Three Probes(示例:配置所有三种探针)
以下是在单个 Deployment 中组合三种探针的完整配置,可根据应用特性调整参数:
apiVersion: apps/v1
kind:Deployment
metadata:
name:web-application
spec:
replicas:3
selector:
matchLabels:
app:web-application
template:
metadata:
labels:
app:web-application
spec:
containers:
-name:web-app
image:my-app:v1.2.3
ports:
-containerPort:8080
# 1. 启动探针:给应用足够的初始化时间
startupProbe:
httpGet:
path:/health/startup# 应用自定义的启动健康检查接口
port:8080
initialDelaySeconds:10# 容器启动后,延迟10秒再开始检查
periodSeconds:5 # 每5秒检查一次
timeoutSeconds:3 # 每次检查超时时间(超过视为失败)
failureThreshold:30 # 允许30次失败(30*5=150秒启动窗口期)
successThreshold:1 # 1次成功即视为启动完成
# 2. 存活探针:确保容器持续健康
livenessProbe:
httpGet:
path:/health/live # 应用自定义的存活检查接口
port:8080
initialDelaySeconds:30# 等待启动探针成功后,再延迟30秒开始检查
periodSeconds:10 # 每10秒检查一次
timeoutSeconds:5
failureThreshold:3 # 连续3次失败则重启容器
successThreshold:1
# 3. 就绪探针:确保容器可接收流量
readinessProbe:
httpGet:
path:/health/ready # 应用自定义的就绪检查接口
port:8080
initialDelaySeconds:5 # 容器启动后5秒开始检查(无需等待启动探针)
periodSeconds:5 # 每5秒检查一次
timeoutSeconds:3
failureThreshold:3 # 连续3次失败则移除流量
successThreshold:1
# 资源限制(配合探针避免资源耗尽)
resources:
requests:
memory:"256Mi"
cpu:"250m"
limits:
memory:"512Mi"
cpu:"500m"
9.3 探针协同工作逻辑
- 启动探针优先执行:容器启动后,启动探针每5秒检查一次,允许150秒内完成初始化(如加载依赖、创建数据库连接)。此阶段,存活探针和就绪探针会暂停,避免误判“未启动完成”为故障。
- 存活探针接管健康监控:启动探针成功后,存活探针每10秒检查一次。若应用死锁(如线程阻塞)导致
/health/live
接口返回非200状态,连续3次失败后,Kubernetes 会自动重启容器,恢复服务。 - 就绪探针控制流量路由:就绪探针独立运行,若应用因临时依赖(如 Redis 缓存宕机)导致
/health/ready
接口失败,Kubernetes 会将该容器从 Service 负载均衡中移除,避免流量发送到“无法处理请求”的实例;当依赖恢复后,探针成功,容器会重新加入流量池。
10. 高级调试技术
标准调试方法(如kubectl logs
、kubectl describe
)可解决大部分日常问题,但面对复杂场景(如性能瓶颈、网络深层问题、生产环境无重启调试),需使用更高级的技术,在不影响业务的前提下定位根因。
10.1 使用临时容器进行实时调试
临时容器(Ephemeral Containers) 是 Kubernetes 1.23+ 支持的特性,可在不重启 Pod、不修改原有容器状态的前提下,临时注入调试容器到运行中的 Pod 内,尤其适合生产环境调试(避免停机)。
10.1.1 基础使用:注入调试容器
场景1:注入轻量调试容器(Busybox)
适用于简单命令(如ping
、ls
)调试:
# 格式:kubectl debug <Pod名> -it --image=<调试镜像> --target=<目标容器名>
kubectl debug web-app-7d4b8c9f-xyz -it --image=busybox --target=web-app
-it
:交互式终端,允许输入命令;--target=web-app
:指定调试目标容器(共享网络、PID 命名空间,可查看目标容器的进程和网络);- 进入容器后,可执行
ps aux
(查看目标容器进程)、netstat -tuln
(查看端口占用)等命令。
场景2:注入带完整工具的容器(Ubuntu/Netshoot)
若需复杂工具(如curl
、tcpdump
、dig
),使用ubuntu
或专门的网络调试镜像nicolaka/netshoot
:
# 注入 Netshoot 容器(适合网络问题调试)
kubectl debug web-app-7d4b8c9f-xyz -it --image=nicolaka/netshoot --target=web-app
10.1.2 实战示例:排查网络连接问题
问题现象:Web 应用间歇性无法连接数据库服务(database-service:5432
)
- 注入 Netshoot 调试容器:
kubectl debug web-app-7d4b8c9f-xyz -it --image=nicolaka/netshoot --target=web-app
- 在调试容器内执行诊断命令:
- 检查 DNS 解析:
nslookup database-service.default.svc.cluster.local # 验证服务域名是否解析到正确IP
dig database-service # 查看DNS服务器返回结果,排查解析延迟/失败
- 测试端口连通性:
telnet database-service 5432 # 检查端口是否开放(连接成功则端口正常)
nc -zv database-service 5432 # 更简洁的端口测试(-z:只检测端口,不发送数据)
- 抓包分析流量:
tcpdump -i any port 5432 -w db-traffic.pcap # 抓取数据库端口流量到文件
# 后续可通过 kubectl cp 下载文件分析:
kubectl cp web-app-7d4b8c9f-xyz:/db-traffic.pcap ./local-pcap/
- 查看网络接口和路由:
ip addr show # 查看Pod内网络接口(确认IP是否在正确网段)
ip route # 查看路由表(确认到数据库服务的路由是否存在)
10.2 kubectl debug扩展场景
kubectl debug
除了注入临时容器,还支持更灵活的调试模式,覆盖节点级、Pod 复制等场景。
10.2.1 场景1:创建Pod调试副本(避免影响原 Pod)
若原 Pod 是生产核心实例,可复制一个完全相同的 Pod 用于调试(修改镜像或配置,不影响原服务):
# 格式:kubectl debug <原Pod名> --copy-to=<新Pod名> --set-image=<原容器名>=<调试镜像> -- sleep 1d
kubectl debug web-app-7d4b8c9f-xyz \
--copy-to=web-app-debug \
--set-image=web-app=ubuntu \ # 将原应用镜像替换为Ubuntu(方便调试)
-- sleep 1d # 让新Pod持续运行1天(足够调试时间)
- 新 Pod 会继承原 Pod 的所有配置(环境变量、挂载卷、资源限制),但使用调试镜像;
- 进入新 Pod 调试:
kubectl exec -it web-app-debug -- bash
# 可执行任意命令(如检查配置文件、测试依赖连接),无需担心影响原服务
10.2.2 场景2:节点级调试(排查节点底层问题)
当节点出现 NotReady
、资源异常(如磁盘满、kubelet 故障)时,可通过 kubectl debug
启动特权容器,直接访问节点的文件系统和系统服务:
# 格式:kubectl debug node/<节点名> -it --image=<调试镜像>
kubectl debug node/worker-node-1 -it --image=ubuntu
- 进入容器后,通过
chroot /host
切换到节点的根文件系统,访问节点级资源:
chroot /host # 切换到节点根目录(相当于直接操作节点)
systemctl status kubelet # 查看kubelet服务状态(排查节点NotReady原因)
journalctl -u kubelet -f # 实时查看kubelet日志(定位启动失败问题)
df -h # 查看节点磁盘使用情况(排查DiskPressure问题)
free -m # 查看节点内存使用(排查MemoryPressure问题)
10.2.3 场景3:性能分析(注入 profiling 容器)
若应用存在 CPU 高占用、内存泄漏,可注入带性能分析工具的容器(如 Go 语言 pprof
):
# 注入 Golang 容器(用于分析 Go 应用性能)
kubectl debug web-app-7d4b8c9f-xyz -it --image=golang:1.21 --target=web-app
- 进入容器后,使用
pprof
分析目标容器的进程:
# 1. 找到目标容器的进程ID(共享PID命名空间,可直接查看)
ps aux | grep web-app # 假设目标进程PID为1234
# 2. 启动pprof,监听端口供本地分析
go tool pprof -http=0.0.0.0:6060 http://localhost:6060/debug/pprof/profile?seconds=30
# 3. 本地端口转发,访问pprof可视化界面
kubectl port-forward web-app-7d4b8c9f-xyz 6060:6060
# 4. 浏览器访问 http://localhost:6060,查看CPU/内存占用热点
10.3 高级调试技术的价值
- 无停机调试:临时容器、Pod 副本等技术避免了生产环境重启,保障业务连续性;
- 深层问题定位:通过
tcpdump
抓包、节点级系统日志查看,可定位网络丢包、kubelet 底层故障等标准工具无法触及的问题; - 上下文保留:调试容器共享目标容器的网络、PID、文件系统命名空间,确保调试环境与实际运行环境一致,避免“本地能复现、生产无法复现”的问题。
总结
Kubernetes 故障排除的核心,从来不是死记硬背命令,而是 “对症下药”,用kubectl describe抓事件、用日志定位容器内部问题、用临时容器避免生产停机,再配合健康检查提前预防故障,每一步都需要结合场景灵活运用。
声明:来自木讷大叔爱运维,仅代表创作者观点。链接:https://eyangzhen.com/3340.html