Kubernetes故障排除存储:解决PVC挂起错误
PersistentVolumeClaim(PVC)挂起状态是Kubernetes中常见的存储问题,会阻止应用程序访问持久化数据。这通常由存储类配置错误、缺少卷供应程序或集群中可用存储不足引起。
步骤1:检查PV和PVC状态
首先列出所有命名空间中的Persistent Volumes(PV)和Persistent Volume Claims(PVC)。此命令提供其状态、访问模式、容量以及是否绑定的概览:
1
|
kubectl get pv,pvc --all-namespaces
|
步骤2:排查挂载问题
要进一步调查处于挂起状态的未绑定PVC,使用以下命令:
检查输出底部的事件部分。通常会显示根本原因,例如:
- 没有匹配的PersistentVolume可用
- 存储类不匹配
- 容量不足
- 缺少供应程序
步骤3:验证存储类
不正确或不存在的存储类是常见原因。列出所有可用的存储类:
1
|
kubectl get storageclass
|
然后描述特定的存储类以检查详细信息,如供应程序和参数:
1
|
kubectl describe storageclass
|
确保您的PVC引用了有效且正确配置的存储类。如果指定的供应程序不存在或拼写错误,卷将无法供应。
步骤4:常见错误和解决方案
假设您定义了一个引用名为fast-ssd存储类的PVC,但供应失败。运行:
1
|
kubectl describe pvc my-data-pvc
|
您可能会看到类似错误:
1
2
|
Warning ProvisioningFailed 3m persistentvolume-controller
storageclass.storage.k8s.io "fast-ssd" not found
|
现在列出所有可用的存储类以确认:
1
|
kubectl get storageclass
|
如果fast-ssd缺失,但gp2或standard存在,请更新您的PVC以使用有效的类。
7. 使用事件和审计日志:深度系统分析
Kubernetes提供了两个强大的调试工具:事件和审计日志。这些帮助您跟踪发生了什么、何时发生以及原因,为您提供系统活动的时间线以进行根本原因分析。
步骤1:理解Kubernetes事件
Kubernetes中的事件记录了集群内部发生的情况。您可以列出所有命名空间中的事件,并按创建时间排序,以在底部查看最近的活动。这有助于将问题与最近的系统行为关联起来。
查看按时间排序的所有事件:
1
|
kubectl get events --all-namespaces --sort-by='.metadata.creationTimestamp'
|
过滤在特定时间后发生的事件:
1
|
kubectl get events --field-selector='lastTimestamp>2023-10-01T10:00:00Z'
|
仅查看警告类型事件(通常表示潜在问题):
1
|
kubectl get events --field-selector type=Warning
|
您还可以使用–watch标志实时监控事件。当您主动进行故障排除并希望在部署或修改资源后立即观察情况时,这很有帮助:
1
|
kubectl get events --watch
|
如果您正在调查特定的pod、部署或服务,可以过滤事件以仅关注该对象。例如:
1
|
kubectl get events --field-selector involvedObject.name=my-pod
|
如果您正在处理pod无法调度的情况,可以过滤原因为"FailedScheduling"的事件。这将显示Kubernetes无法将pod放置在节点上的原因,例如由于资源不足或亲和性冲突:
1
|
kubectl get events --field-selector reason=FailedScheduling
|
步骤2:使用审计日志进行深度故障排除
虽然事件帮助您了解正在发生什么,但审计日志让您可以看到谁在API级别做了什么——这对于安全调查或跟踪管理操作至关重要。
审计日志默认未启用。要启用它们,您必须配置审计策略。以下是一个示例审计策略配置,捕获核心资源(如pod、服务、部署等)的详细日志:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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"]
|
一旦配置,审计日志可以帮助您跟踪以下问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "4d2c8b7a-f3e1-4b2a-9c8d-1e3f5a7b9c2d",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/production/pods/web-app-7d4b8c9f-xyz",
"verb": "delete",
"user": {
"username": "admin@company.com",
"groups": ["system:authenticated"]
},
"sourceIPs": ["192.168.1.100"],
"userAgent": "kubectl/v1.28.0",
"objectRef": {
"resource": "pods",
"namespace": "production",
"name": "web-app-7d4b8c9f-xyz"
},
"responseStatus": {
"code": 200
},
"requestReceivedTimestamp": "2024-01-15T10:30:00.000Z",
"stageTimestamp": "2024-01-15T10:30:00.123Z"
}
|
一旦启用审计日志,日志将显示重要细节,例如:
- 哪个用户发出了API请求
- 来自哪个IP地址
- 使用的HTTP动词(例如GET、POST、DELETE)
- 受影响的资源(例如pod、部署)
- 操作的时间戳
- 请求是否成功
示例:审计日志可能显示在特定时间,由特定的管理员用户从某个IP地址删除了一个pod。这种透明度在诊断由意外或未经授权的更改引起的问题时至关重要。
8. 使用Kubernetes仪表板和可视化工具
虽然像kubectl这样的命令行工具提供了检查Kubernetes集群的强大方式,但可视化工具简化了集群管理,特别是在识别跨指标、日志和事件的模式时。
步骤1:Kubernetes仪表板概述
Kubernetes仪表板是一个基于Web的用户界面,让您可以可视化地管理集群资源。它提供了对部署、资源使用情况、日志和事件的详细洞察,使得无需运行多个CLI命令即可更轻松地诊断问题。
由于安全考虑,默认情况下仪表板未在生产环境中安装。但是,可以手动部署如下:
- 部署仪表板:运行以下命令以应用推荐的配置:
1
|
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
|
- 创建服务账户以进行访问:
1
2
|
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
|
- 生成访问令牌:
1
|
kubectl create token dashboard-admin -n kubernetes-dashboard
|
一旦部署,仪表板允许您:
- 随时间监控CPU和内存使用情况
- 可视化事件时间线
- 探索Kubernetes资源之间的关系
- 直接在浏览器中流式传输应用程序日志
示例用例:
假设您的应用程序遇到间歇性故障。仪表板可能显示CPU使用率峰值与这些故障一致,并且事件日志显示pod正在被OOMKilled。这种模式通过视觉识别比阅读原始CLI日志更容易。
9. 实施健康检查和探针
Kubernetes中的健康检查类似于常规医疗检查,有助于及早发现问题并确保一切按预期运行。
Kubernetes使用探针来监控应用程序容器的健康状况和可用性。这些探针使集群能够检测问题并采取自动操作,例如在必要时重启容器或停止流量路由。
理解就绪性和存活探针
Kubernetes提供三种类型的探针,每种在维护容器健康方面扮演特定角色:
- 存活探针:检查容器是否仍在运行。如果重复失败,Kubernetes会重启容器。
- 就绪探针:检查容器是否准备好接受流量。如果失败,容器会暂时从服务端点中移除。
- 启动探针:为容器提供额外时间来完成其启动逻辑,然后再开始其他探针。这对于启动时间较长的应用程序很有用。
示例:配置所有三种探针
以下是在单个部署中组合所有三种探针的配置示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
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
# 启动探针 - 给应用时间初始化
startupProbe:
httpGet:
path: /health/startup
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30 # 30 * 5 = 150秒启动时间
successThreshold: 1
# 存活探针 - 如果不健康则重启容器
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
# 就绪探针 - 如果未准备好则从服务中移除
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
|
这些探针如何协同工作
- 启动探针:首先检查此探针。它每5秒运行一次,允许最多150秒让应用程序完成启动任务,例如初始化数据库或加载配置。在此期间,其他探针暂停。
- 存活探针:一旦启动探针成功,存活探针接管。它确保容器保持健康。如果检查连续失败三次,Kubernetes会自动重启容器。
- 就绪探针:这确保容器准备好处理传入流量。如果检查失败(例如由于临时数据库中断),Kubernetes会暂时从负载均衡器中移除pod而不重启它。
10. 高级调试技术
虽然标准的Kubernetes调试方法处理许多日常问题,但有时需要更高级的技术,特别是用于诊断复杂的性能瓶颈、意外的应用程序行为或基本工具无法解决的深层网络级问题。
步骤1:使用临时容器进行实时调试
临时容器是一种强大的方式,可以在不重启pod或改变其状态的情况下对实时应用程序进行故障排除。它们允许您将调试容器临时注入到运行的pod中,非常适合正常运行时间至关重要的生产调试。
例如,要在运行的pod中启动基本调试容器:
1
|
kubectl debug -it --image=busybox --target=<pod-name>
|
要包含特定的调试工具(如bash、curl、dig),使用像Ubuntu这样的镜像:
1
|
kubectl debug database-pod -it --image=ubuntu --target=postgres -- bash
|
实际示例:网络问题调查
假设您的Web应用程序面临间歇性连接问题。您可以使用像netshoot这样的网络工具附加调试容器:
1
|
kubectl debug web-app-7d4b8c9f-xyz -it --image=nicolaka/netshoot --target=web-app
|
在调试容器内部,我们现在可以检查网络连接:
1
2
|
ping database-service
nslookup database-service
|
在调试容器内部,您可以执行多种诊断:
检查服务连接性:
1
2
|
ping database-service
nslookup database-service
|
测试开放端口:
1
|
telnet database-service 5432
|
检查网络接口:
1
2
|
ip addr show
ss -tuln
|
验证DNS解析:
1
|
dig database-service.default.svc.cluster.local
|
监控网络流量:
1
|
tcpdump -i any port 5432
|
检查运行进程:
并检查文件系统:
1
2
|
ls -la /app/
cat /app/config.yaml
|
这种实时环境调试允许精确定位可能仅在真实生产条件下发生的问题。
步骤2:利用kubectl debug进行更广泛的场景
kubectl debug命令还支持超越临时容器的更高级操作:
创建pod的完整调试副本:
1
|
kubectl debug web-app-7d4b8c9f-xyz --copy-to=web-app-debug --image=ubuntu --set-image=web-app=ubuntu -- sleep 1d
|
您还可以创建具有相同配置但不同镜像的新pod:
1
|
kubectl exec -it web-app-debug -- bash
|
在节点级别调试:您可以在节点上启动特权pod以调查节点级问题:
1
|
kubectl debug node/worker-node-1 -it --image=ubuntu
|
在特权容器内部,您可以访问主机的文件系统和服务:
1
2
3
|
chroot /host bash
systemctl status kubelet
journalctl -u kubelet -f
|
添加性能分析容器以进行性能分析:如果您正在调查CPU分析或内存泄漏,带有Go或其他性能分析工具的容器可以帮助:
1
|
kubectl debug web-app-7d4b8c9f-xyz -it --image=golang:1.21 --target=web-app
|
为什么这些技术很重要
高级调试不仅仅是拥有额外的命令;它是在不影响生产工作负载的情况下访问低级细节的灵活性。通过临时容器、节点级访问和完整的pod复制,您可以在上下文中实时排除几乎所有问题,最大限度地减少猜测和停机时间。
结论
有效地排除Kubernetes故障依赖于知道何时以及如何应用正确的调试方法。像kubectl、事件和审计日志这样的工具对于日常调试至关重要。然而,将这些与专用的Kubernetes可观测性平台结合可以增强可见性,减少MTTR(平均解决时间),并确保在您的Kubernetes环境中更顺畅的操作。