Kubernetes 生产环境常见问题与排查命令总结
运维工程师在日常工作中,Kubernetes 集群的稳定性直接决定了业务服务的可用性。生产环境中,Pod 启动失败、Node 不可用、Service 访问异常、存储挂载报错等问题几乎每天都会遇到。本文从一线运维视角出发,系统梳理 Kubernetes 生产环境中最常见的问题现象、排查思路、关键命令和修复方案,形成可直接照着操作的故障排查手册。
一、问题背景与适用场景
1.1 背景说明
Kubernetes 作为容器编排平台,其复杂度远高于传统虚拟机或物理机。一个看似简单的 Pod 启动失败,可能涉及镜像、网络、存储、调度、权限等多个层面的配置问题。在生产环境中,往往需要快速定位问题、避免业务中断,同时不能因为误操作引发更大的故障。
本文的排查思路适用于以下场景:
开发、测试、预发布、生产各环境
基于 kubeadm、kops、Rancher、TKE、EKS、ACK 等方式部署的集群
使用 Deployment、StatefulSet、DaemonSet、Job、CronJob 等控制器部署的工作负载
有状态应用(MySQL、Redis)与无状态 Web 服务混合部署的场景
1.2 阅读前提
阅读本文需要具备以下基础知识:
了解 Kubernetes 基本概念:Pod、Node、Namespace、Deployment、Service、Ingress、PersistentVolumeClaim、ConfigMap、Secret
熟悉 kubectl 基本操作
了解 Linux 基础命令:ps、top、df、mount、netstat/ss、curl、dig、kubectl
了解 Docker 基础概念:镜像、容器、卷
1.3 排查原则
在进入具体问题之前,先明确几个排查原则:
分层排查,从下往上:先看 Node 状态,再看 Pod 状态,最后看应用日志。不要一上来就看 Pod 内部,这样容易忽略底层基础设施问题。
先看状态,再看日志:kubectl get pod 的 STATUS 列往往已经能给出初步判断方向,CrashLoopBackOff 和 ImagePullBackOff 的处理路径完全不同。
不要轻易重启:重启 Pod 会丢失现场,日志和事件信息会部分丢失。如果必须重启,先保存关键信息。
生产操作必须备份配置:修改 Deployment、Service、ConfigMap 等资源前,先将当前配置导出备份。
kubectl get deployment-n -o yaml > backup_ .yaml
高风险操作要确认影响范围:删除 Pod、删除 Namespace、修改 RBAC 权限等操作前,必须确认影响范围,最好在非业务高峰期执行。
二、Pod 常见问题与排查
Pod 是 Kubernetes 最基础的调度单元,Pod 启动失败是最常见的问题类型。Pod 的状态(STATUS)字段是判断问题方向的第一线索。
2.1 CrashLoopBackOff
2.1.1 现象描述
Pod 处于 CrashLoopBackOff 状态,Pod 内容器反复重启,每次重启间隔时间逐渐增长(通常为 10s、20s、40s、80s)。
kubectl get pod -nNAME READY STATUS RESTARTS AGE my-app-5d8f9c6b4-x7r2k 0/1 CrashLoopBackOff 3 2m15s
2.1.2 初步判断
CrashLoopBackOff 表示容器进程启动后立即退出,退出码非零。常见原因包括:
应用配置文件错误或缺失
应用启动命令或参数错误
依赖服务(数据库、Redis、API)不可达
健康检查(livenessProbe)失败导致 kubelet 杀死容器
权限不足(文件读取、端口绑定)
动态链接库缺失
容器内OOM(内存不足被内核杀掉)
2.1.3 排查步骤
第一步:查看 Pod 事件和状态详情
kubectl describe pod-n
重点关注 Events 段和 Last State 段:
Last State: Terminated Reason: OOMKilled Exit Code: 137
OOMKilled 说明容器内存超限,被内核杀掉。如果不是 OOMKilled,继续往下看。
第二步:查看容器日志
如果 Pod 还在运行(虽然 Restarting),用以下命令查看上一次容器的退出日志:
# 查看上一个终止容器的日志 kubectl logs-n --previous # 如果是多容器 Pod,指定容器名 kubectl logs -n -c --previous
如果日志显示 "connection refused" 或 "connection timeout",说明应用启动依赖的服务不可达。如果日志显示配置文件找不到,检查 ConfigMap 和 Secret 是否正确挂载。
第三步:检查资源限制
kubectl get pod-n -o jsonpath='{.spec.containers[*].resources}'
如果 limits.memory 设置过低,容器启动后很容易被 OOMKill。重点关注 requests 和 limits 的关系:
resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "128Mi" cpu: "200m"
requests.memory 和 limits.memory 设置相同值,意味着没有内存突发能力。MySQL、Java 应用等内存敏感型工作负载,建议 limits.memory 设为 requests.memory 的 1.5-2 倍。
第四步:检查 Liveness Probe 配置
如果 describe 输出中有如下事件:
Warning Unhealthy 2m ago kubelet Liveness probe failed: HTTP probe failed with statuscode: 503
说明应用启动后健康检查持续失败,kubelet 强制杀死了容器。这种情况并非应用完全崩溃,而是健康检查配置不当或应用启动时间过长。
排查方法:
kubectl get pod-n -o jsonpath='{.spec.containers[*].livenessProbe}'
检查 initialDelaySeconds 是否设置过短。对于 Java、Go 等编译型语言构建的应用,首次加载时间较长,建议 initialDelaySeconds 不少于 30 秒,periodSeconds 不少于 10 秒。
第五步:进入容器内部排查
如果以上步骤还不能定位根因,进入容器内部进一步排查:
kubectl exec -it-n -- /bin/sh # 查看进程状态 ps aux # 查看打开的文件描述符 ls -la /proc/1/fd # 查看网络连接状态 cat /proc/net/tcp cat /proc/net/tcp6 # 查看 DNS 配置 cat /etc/resolv.conf # 测试网络连通性 ping -c 3 kubernetes.default.svc curl -v http://localhost: /health # 查看系统日志(如果有权限) dmesg | tail -50
2.1.4 常见修复方案
依赖服务不可达:检查依赖服务的 Endpoint 是否存在:
kubectl get endpoints-n
如果 Endpoints 为空,说明 Service 关联的 Pod 不存在或不健康。需要检查后端 Pod 是否正常运行。
OOMKilled:调整资源限制或优化应用内存使用:
kubectl patch deployment-n -p '{"spec":{"template":{"spec":{"containers":[{"name":" ","resources":{"limits":{"memory":"512Mi"}}}]}}}}'
配置文件错误:检查 ConfigMap 和 Secret 是否正确挂载:
kubectl get pod-n -o jsonpath='{.spec.volumes}'
挂载路径和配置文件名是否与应用期望的一致。
健康检查配置不当:调整 livenessProbe 参数:
livenessProbe: httpGet: path:/health port:8080 initialDelaySeconds:30 periodSeconds:10 failureThreshold:3
2.1.5 验证方式
修复后观察 Pod 是否进入 Running 状态:
watch kubectl get pod-n
确认 READY 列为 1/1(或实际容器数量),STATUS 为 Running,RESTARTS 不再增长。用以下命令确认应用功能正常:
kubectl exec -it-n -- curl -s http://localhost: /health
2.2 ImagePullBackOff
2.2.1 现象描述
Pod 处于 ImagePullBackOff 或 ErrImagePull 状态,无法拉取容器镜像。
kubectl get pod -nNAME READY STATUS RESTARTS AGE my-app-5d8f9c6b4-x7r2k 0/1 ImagePullBackOff 0 5m
2.2.2 初步判断
ImagePullBackOff 的常见原因:
镜像名称拼写错误或标签不存在
私有镜像仓库未配置 imagePullSecrets
镜像仓库认证信息过期
镜像仓库网络不通(防火墙、节点 DNS 异常)
镜像仓库证书过期或不受信任
Node 没有拉取该镜像的权限(节点级别)
2.2.3 排查步骤
第一步:查看 Pod 事件
kubectl describe pod-n
重点关注 Events:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Failed 2m ago kubelet Failed to pull image "registry.example.com/myapp:v1.2": rpc error: code = Unknown desc = Error: Not war: ... Warning Failed 2m ago kubelet Error: ErrImagePull Normal BackOff 2m ago kubelet Back-off pulling image "registry.example.com/myapp:v1.2"
错误信息会直接告诉你原因:是不存在的镜像、网络不通、还是认证失败。
第二步:检查镜像名称和标签
# 直接在 Node 上尝试拉取镜像(如果有权限) docker pull# 或者用 crictl(如果使用 containerd) crictl pull
如果镜像标签不存在,会返回 "manifest unknown"。如果是网络问题,会返回 timeout。
第三步:检查 imagePullSecrets
kubectl get pod-n -o jsonpath='{.spec.imagePullSecrets}'
如果使用的是私有仓库,但没有配置 imagePullSecrets,Pod 无法认证拉取镜像。
查看现有的 Secret:
kubectl get secrets -n| grep -i docker
创建私有仓库认证 Secret:
kubectl create secret docker-registry--docker-server= --docker-username= --docker-password= --docker-email= -n
将 Secret 关联到 Pod 或 ServiceAccount:
# 关联到 Pod(每个 Pod 都要加) kubectl patch deployment-n -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":" "}]}}}}' # 关联到 ServiceAccount(该 SA 下的所有 Pod 都生效) kubectl patch serviceaccount default -n -p '{"imagePullSecrets":[{"name":" "}]}'
第四步:检查节点级别镜像拉取策略
节点上的 kubelet 日志可能提供更多信息:
# journalctl 查看 kubelet 日志(需要节点权限) journalctl -u kubelet --no-pager | grep -A5 "ImagePullBackOff" # 如果是 containerd journalctl -u containerd --no-pager | grep -i pull
第五步:检查镜像仓库网络连通性
从 Pod 所在节点测试网络:
# 解析镜像仓库域名 nslookup registry.example.com # 测试 443 端口连通性 nc -zv registry.example.com 443 # 测试 HTTP 响应 curl -v https://registry.example.com/v2/
2.2.4 常见修复方案
镜像不存在:使用正确标签重新部署,或先在本地拉取测试:
docker pulldocker tag
认证失败:更新 imagePullSecrets 中的凭证,或重建 Secret:
kubectl delete secret-n kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= -n
网络不通:检查集群网络插件、DNS 服务、节点安全组规则。
证书问题:如果使用自签名证书,需要在所有 Node 的 /etc/docker/certs.d/ 目录下配置受信任证书。
2.2.5 验证方式
修复后,删除 Pod 触发重新调度:
kubectl delete pod-n watch kubectl get pod -n
观察 Pod 是否正常拉取镜像并进入 Running 状态。
2.3 Pending 状态
2.3.1 现象描述
Pod 长时间处于 Pending 状态,既不运行也不报错。
kubectl get pod -nNAME READY STATUS RESTARTS AGE my-app-5d8f9c6b4-x7r2k 0/1 Pending 0 10m
2.3.2 初步判断
Pending 状态表示 Pod 已经被 Kubernetes API 接受,但调度器无法将其调度到合适的 Node 上。原因可能包括:
没有 Node 满足 Pod 的资源请求(CPU/内存)
没有 Node 满足 Pod 的调度约束(亲和性、污点容忍)
持久卷(PVC)处于 Pending 状态,Pod 等待存储挂载
调度器故障
节点存在污点但 Pod 没有配置对应的容忍
2.3.3 排查步骤
第一步:查看 Pod 事件
kubectl describe pod-n
重点看 Events 和 Conditions:
Conditions: Type Status PodScheduled False Reason : Unschedulable Message : 0/3 nodes are available: 1 Insufficient memory, 2 node(s) had taints that the pod didn't tolerate.
从 Message 可以直接看出原因:资源不足(Insufficient memory)或污点不匹配。
第二步:检查集群资源状况
# 查看所有节点状态和资源使用 kubectl top nodes # 如果 metrics-server 未安装,用以下命令查看资源分配情况 kubectl describe nodes | grep -A5 "Allocated resources" # 查看每个节点的 CPU 和内存请求对比 kubectl get pods -n-o wide
第三步:检查污点(Taints)和容忍(Tolerations)
# 查看节点污点
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.spec.taints[*].key}{"
"}{end}'
# 查看 Pod 的容忍配置
kubectl get pod -n -o jsonpath='{.spec.tolerations}'
如果节点有 node.kubernetes.io/not-ready:NoExecute 污点,而 Pod 没有配置对应的容忍,Pod 将无法调度。
第四步:检查亲和性配置
kubectl get pod-n -o jsonpath='{.spec.affinity}'
检查 nodeAffinity、podAffinity、podAntiAffinity 配置是否过于严格。
第五步:检查 PVC 状态
如果 Pod 使用了持久存储:
kubectl get pvc -nkubectl describe pod -n | grep -A10 "Volumes"
如果 PVC 处于 Pending,Pod 会等待存储绑定:
kubectl get pvc -nNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS data-myapp-0 Pending slow-storage
2.3.4 常见修复方案
资源不足:增加 Node 扩容,或调整 Pod 资源请求:
# 水平扩缩容 Deployment(如果使用 HPA) kubectl scale deployment-n --replicas=2 # 调整 Pod 资源请求 kubectl patch deployment -n -p '{"spec":{"template":{"spec":{"containers":[{"name":" ","resources":{"requests":{"memory":"256Mi","cpu":"200m"}}}]}}}}'
污点问题:给 Pod 添加匹配的容忍,或者移除节点污点(谨慎操作):
# 添加污点容忍到 Pod kubectl patch deployment-n -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}]}}}}}'
PVC Pending:检查存储类是否存在,PVC 配置是否正确:
kubectl get storageclass kubectl describe pvc-n
如果是存储类问题,可能需要创建 StorageClass 或等待存储管理员提供存储后端。
2.3.5 验证方式
修复后观察 Pod 是否被调度并进入 Running:
watch kubectl get pod-n
2.4 Terminating 状态卡死
2.4.1 现象描述
Pod 长时间(超过几分钟)处于 Terminating 或 ContainerCreating 状态,删除不掉。
kubectl get pod -nNAME READY STATUS RESTARTS AGE my-app-5d8f9c6b4-x7r2k 1/1 Terminating 0 30m
2.4.2 初步判断
Pod 卡在 Terminating 通常是因为:
Finalizers 引用了不存在的资源
存储卷挂载未清理
容器进程未正常退出
kubelet 与 API Server 通信异常
网络插件问题导致挂载点卡死
2.4.3 排查步骤
第一步:查看 Pod 详细状态
kubectl get pod-n -o yaml
检查 spec.finalizers 是否存在,spec.deletionTimestamp 是否有值。
第二步:检查 kubelet 日志
在 Pod 所在的 Node 上查看 kubelet 日志:
journalctl -u kubelet --no-pager | grep -E "(pod|%s)" | tail -100
第三步:检查容器进程
# 在 Node 上查看容器进程 crictl ps -a | grep# 查看是否有僵尸进程 ps aux | grep -E "(zombie| )"
第四步:检查存储挂载
# 查看该 Pod 使用的卷 kubectl get pod-n -o jsonpath='{.spec.volumes[*].name}' # 在 Node 上查看挂载点 mount | grep df -h | grep
2.4.4 强制删除方案
如果确认 Pod 确实无法正常终止,可以强制删除:
# 方式一:删除时跳过 finalizers kubectl patch pod-n -p '{"metadata":{"finalizers":null}}' --type=merge # 方式二:设置较短的宽限期后强制终止 kubectl delete pod -n --grace-period=5 --force
警告:强制删除前必须确认 Pod 上的业务数据已备份,强制删除可能导致数据不一致。对于有状态应用,优先调查挂载问题而不是直接强制删除。
第五步:检查 CSI 和存储插件
如果存储挂载卡死,查看存储插件 Pod 的日志:
kubectl get pods -n kube-system | grep -E "csi|storage" kubectl logs -n kube-system--tail=100
2.4.5 常见修复方案
Finalizers 问题:移除 finalizers 后删除:
kubectl patch pod-n -p '{"metadata":{"finalizers":null}}' --type=merge
挂载卡死:重启 kubelet 或重置容器运行时(谨慎操作):
# 重启 kubelet systemctl restart kubelet # 如果是 containerd,重启 containerd systemctl restart containerd
网络插件问题:检查 CNI 插件状态:
kubectl get pods -n kube-system | grep -E "calico|flannel|cilium|weave" kubectl logs -n kube-system--tail=50
2.4.6 验证方式
删除后确认 Pod 已消失:
kubectl get pod-n
如果需要重建 Pod,确认新 Pod 能正常启动。
三、Node 常见问题与排查
Node 是 Pod 运行的基础底层,Node 不可用会直接影响其上所有 Pod。
3.1 NotReady 状态
3.1.1 现象描述
Node 状态变为 NotReady,对应的所有 Pod 不再被调度,但已运行的 Pod 仍然维持运行(除非使用 DaemonSet 或强制驱逐)。
kubectl get nodes NAME STATUS ROLES AGE VERSION node-1 Ready control-plane 90d v1.28.0 node-2 NotReady60d v1.28.0
3.1.2 初步判断
Node 进入 NotReady 状态,通常是因为节点上的 kubelet 进程无法与 API Server 保持心跳(默认 40 秒内没有心跳视为 not ready)。常见原因:
节点资源耗尽(CPU/内存/磁盘)
kubelet 进程崩溃或 OOM
节点网络异常
kubelet 配置错误
容器运行时故障
内核问题(文件描述符耗尽、内存耗尽)
3.1.3 排查步骤
第一步:在 Master 节点查看节点详情
kubectl describe node
重点关注 Conditions 和 Events:
Conditions: Type Status MemoryPressure True # 内存压力 DiskPressure True # 磁盘压力 PIDPressure False # 进程数压力 NetworkUnavailable False # 网络不可用 Ready False # kubelet 未就绪
如果有条件为 True,说明节点存在对应问题。
第二步:SSH 到问题节点上进一步排查
# 查看 kubelet 状态 systemctl status kubelet # 查看 kubelet 日志 journalctl -u kubelet --no-pager -n 100 # 查看系统资源 top df -h free -h
第三步:检查磁盘空间
磁盘空间不足是 Node NotReady 的最常见原因之一。
df -h # 检查 Docker/容器数据目录大小 du -sh /var/lib/docker/* du -sh /var/lib/containers/* # 检查日志目录大小 du -sh /var/log/*
Kubernetes 要求 Docker 的存储驱动分区至少有 20% 空闲空间。如果磁盘空间低于 20%,kubelet 会标记节点为 DiskPressure,导致 Pod 驱逐和新 Pod 无法调度。
第四步:检查内存
free -h vmstat 1 5
内存不足时,内核会触发 OOM Killer,可能杀掉了 kubelet 进程。
第五步:检查 kubelet 进程
ps aux | grep kubelet systemctl restart kubelet journalctl -u kubelet --no-pager -n 50
3.1.4 常见修复方案
磁盘空间不足:清理磁盘空间:
# 清理旧的容器镜像和未使用的卷 docker system prune -af # 或者如果使用 containerd crictl rmi --prune # 清理日志文件(谨慎操作) journalctl --vacuum-time=7d # 清理旧的 kubelet 日志 truncate -s 0 /var/log/kubelet.log
kubelet 故障:重启 kubelet:
systemctl restart kubelet systemctl status kubelet
资源耗尽:优化节点负载或扩缩容节点:
# 查看各 Pod 的资源使用 kubectl top pod -n--sort-by=memory
对于内存压力节点,检查是否有单个 Pod 内存使用超出 limits。
3.1.5 验证方式
kubectl get node
STATUS 变为 Ready 后,确认节点状态正常。等待几分钟后,确认不再出现 NotReady。
3.2 节点资源压力
3.2.1 内存压力(MemoryPressure)
当节点内存不足时,kubelet 会设置 MemoryPressure=true,并开始驱逐 Pod。驱逐策略基于 Pod 的 QoS 级别:BestEffort(无资源请求)Pod 最先被驱逐。
排查方法:
# 在节点上查看内存使用 free -h cat /proc/meminfo | grep -E "MemAvailable|MemFree" # 查看哪些 Pod 内存使用最高 kubectl top pod -A --sort-by=memory | head -20
修复方案:
将内存密集型 Pod 分散到多个节点
提高内存请求(requests.memory)以获得更高 QoS 保障
增加节点内存或扩容
3.2.2 磁盘压力(DiskPressure)
当磁盘空间不足时,kubelet 会拒绝调度新 Pod 到该节点。
排查方法:
# 查看磁盘使用
df -h
# 查看 Docker 使用的磁盘
docker system df
# 查看大文件
find /var/log -type f -size +100M -exec ls -lh {} ;
修复方案:
# 清理未使用的 Docker 资源
docker system prune -af --volumes
# 清理旧的日志
find /var/log -type f -name "*.log" -mtime +7 -exec truncate -s 0 {} ;
3.2.3 PID 压力(PIDPressure)
当节点进程数接近上限时,kubelet 会标记 PIDPressure。新 Pod 如果有 PID 限制,可能无法调度。
排查方法:
# 查看 PID 使用 cat /proc/sys/kernel/pid_max ps aux | wc -l
修复方案:增加 pid_max 或降低 Pod 的 PID 限制。
3.3 节点网络异常
当节点网络不可用时,kubelet 无法与 API Server 通信,节点状态变为 NetworkUnavailable。
排查方法:
# 在节点上测试网络 ping -c 3 8.8.8.8 ping -c 3# 查看 DNS 解析 nslookup kubernetes.default.svc # 查看网络接口 ip addr ip route
四、Service 与网络常见问题
Service 是 Kubernetes 服务发现的核心,Service 访问异常会直接导致业务不可用。
4.1 Endpoints 缺失
4.1.1 现象描述
Service 存在但 Endpoints 为空,访问 Service 时连接失败。
kubectl get svc-n NAME TYPE CLUSTER-IP PORT(S) AGE my-service ClusterIP 10.96.45.123 80/TCP 30d kubectl get endpoints -n NAME ENDPOINTS AGE my-service 30d
4.1.2 初步判断
Endpoints 为空说明没有 Pod 被 Service 选中。常见原因:
Selector 标签与 Pod 标签不匹配
后端 Pod 不在 Running 状态
Pod 与 Service 不在同一个 Namespace
4.1.3 排查步骤
第一步:检查 Service 的 Selector
kubectl get svc-n -o jsonpath='{.spec.selector}'
第二步:检查后端 Pod 的标签
kubectl get pods -n--show-labels | grep
第三步:测试标签选择
kubectl get pods -n-l " = "
如果 Service 的 Selector 和 Pod 的标签不匹配,Endpoints 就不会有任何条目。
4.1.4 修复方案
方案一:修改 Service Selector
kubectl patch svc-n -p '{"spec":{"selector":{"app":" "}}}'
方案二:修改 Pod 标签(临时修复,不推荐长期使用)
kubectl label pod-n --overwrite app=
方案三:使用 Endpoints(手动管理)
对于不支持标签选择器的场景,可以手动创建 Endpoints:
apiVersion: v1 kind:Endpoints metadata: name:my-service namespace:subsets: -addresses: -ip:192.168.1.100 ports: -port:8080 protocol:TCP
4.1.5 验证方式
kubectl get endpoints-n
确认 Endpoints 有值后,从 Pod 内访问 Service 测试连通性:
kubectl exec -it-n -- curl -v http://my-service. .svc.cluster.local
4.2 DNS 解析异常
4.2.1 现象描述
Pod 内无法通过 Service 名称访问其他服务,报 "could not resolve host" 错误。
kubectl exec -it-n -- nslookup my-service # 或 kubectl exec -it -n -- curl http://my-service
返回 "server can't find my-service" 或 "Name or service not known"。
4.2.2 初步判断
DNS 解析失败的常见原因:
kube-dns 或 CoreDNS Pod 不正常
Pod 的 /etc/resolv.conf 配置错误
NetworkPolicy 阻止了 DNS 流量
节点 DNS 配置与集群 DNS 不一致
4.2.3 排查步骤
第一步:检查 DNS Pod 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns # 或者 kubectl get pods -n kube-system -l app.kubernetes.io/name=coredns
CoreDNS Pod 应该处于 Running 状态,READY 应该为 1/1。
第二步:查看 DNS Pod 日志
kubectl logs -n kube-system--tail=50
如果有查询失败的日志,会显示具体的查询和错误信息。
第三步:检查 Pod 内 DNS 配置
kubectl exec -it-n -- cat /etc/resolv.conf
正常的 DNS 配置应该类似:
nameserver 10.96.0.10 search.svc.cluster.local svc.cluster.local cluster.local options ndots:5
nameserver 地址应该与集群的 kube-dns 服务 IP 一致。
第四步:从 DNS Pod 直接测试查询
kubectl exec -it -n kube-system-- cat /etc/resolv.conf # 使用 nslookup 或 dig(如果 Pod 内有这些工具) kubectl exec -it -n kube-system -- nslookup kubernetes.default
第五步:检查 NetworkPolicy
如果集群启用了 NetworkPolicy,确认没有规则阻止 DNS 流量:
kubectl get networkpolicy -nkubectl describe networkpolicy -n
4.2.4 常见修复方案
DNS Pod 不正常:重启 DNS Pod:
kubectl delete pod -n kube-system -l k8s-app=kube-dns # 或 kubectl rollout restart deployment/coredns -n kube-system
DNS Service IP 不对:检查 kube-dns 或 CoreDNS 的 Service:
kubectl get svc kube-dns -n kube-system # 或者 kubectl get svc coredns -n kube-system
Pod DNS 配置错误:检查 kubelet 的 --cluster-dns 参数是否与 DNS Service IP 一致。
4.2.5 验证方式
从 Pod 内测试 DNS 解析:
kubectl exec -it-n -- nslookup kubernetes.default kubectl exec -it -n -- nslookup my-service. .svc.cluster.local
4.3 NetworkPolicy 误配置
NetworkPolicy 是 Kubernetes 提供的网络隔离机制,配置错误会导致 Pod 无法通信。
4.3.1 现象描述
Pod 无法访问特定 Service 或被特定 Pod 访问,NetworkPolicy 应用后才出现此问题。
4.3.2 排查步骤
第一步:查看 Namespace 或 Pod 的 NetworkPolicy
kubectl get networkpolicy -nkubectl describe networkpolicy -n
第二步:分析 NetworkPolicy 规则
NetworkPolicy 是白名单机制,只有明确允许的流量才能通过。如果 Pod 需要接收来自其他 Pod 或外部的流量,必须有对应的 Ingress 规则。
第三步:检查 Pod 是否被正确选中
kubectl get pod-n --show-labels
4.3.3 修复方案
如果确认是 NetworkPolicy 导致的问题,可以临时删除 Policy 验证:
kubectl delete networkpolicy-n
验证恢复后,重新编写正确的 NetworkPolicy 规则。
NetworkPolicy 规则示例——允许同一 Namespace 内的 Pod 访问:
apiVersion: networking.k8s.io/v1 kind:NetworkPolicy metadata: name:allow-same-namespace namespace:spec: podSelector:{} policyTypes: -Ingress ingress: -from: -podSelector:{}
4.4 Ingress 故障
4.4.1 现象描述
外部无法通过 Ingress 域名访问服务,浏览器返回 404 或超时。
4.4.2 排查步骤
第一步:检查 Ingress Controller Pod 状态
kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx # 或 kubectl get pods -n kube-system | grep -E "nginx|ingress"
Ingress Controller Pod 应该处于 Running 状态。
第二步:检查 Ingress 资源
kubectl get ingress -nkubectl describe ingress -n
第三步:检查 Ingress Class
确认 Ingress 使用的是集群中已部署的 Ingress Class:
kubectl get ingressclass kubectl get ingress-n -o jsonpath='{.spec.ingressClassName}'
第四步:检查后端 Service 和 Endpoints
kubectl get svc -nkubectl get endpoints -n
第五步:从 Ingress Controller Pod 内测试
kubectl exec -it -n ingress-nginx-- curl -v http:// . .svc.cluster.local:
五、存储常见问题
有状态应用的存储问题往往比无状态应用更复杂,且风险更高。
5.1 PVC Pending
5.1.1 现象描述
PersistentVolumeClaim 处于 Pending 状态,Pod 无法启动。
kubectl get pvc -nNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS data-myapp-0 Pending standard
5.1.2 初步判断
PVC Pending 的常见原因:
存储类(StorageClass)不存在
存储后端(CSI)不可用
存储配额不足
没有匹配的 PV(静态供给场景)
PVC 的 accessModes 与可用的 PV 不匹配
5.1.3 排查步骤
第一步:查看 PVC 事件
kubectl describe pvc-n
Events 段会显示具体原因:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ProvisioningFailed 5m persistentvolume-controller Failed to provision volume: no storage class "slow-storage"
第二步:检查 StorageClass
kubectl get storageclass
如果 PVC 引用的 StorageClass 不存在,需要创建:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
第三步:检查 CSI 驱动和存储插件
kubectl get pods -n kube-system | grep -E "csi|storage" kubectl get csidriver
如果使用云厂商的 CSI(如 AWS EBS、Azure Disk、GCP PD),检查对应的 CSI Pod:
kubectl get pods -n kube-system | grep -E "ebs|disk|azuredisk|gcp-pd"
第四步:检查 PVC 的 accessModes
kubectl get pvc-n -o jsonpath='{.spec.accessModes}' kubectl get pv -o jsonpath='{.spec.accessModes}'
常见 accessModes:
ReadWriteOnce:单个节点读写
ReadOnlyMany:多节点只读
ReadWriteMany:多节点读写(需要特定存储后端,如 NFS、CephFS)
5.1.4 常见修复方案
StorageClass 不存在:创建 StorageClass 或使用默认存储类:
# 将某存储类设为默认 kubectl patch storageclass-p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
等待动态供给:对于 WaitForFirstConsumer 模式的存储类,需要调度一个 Pod 触发绑定。
CSI 问题:检查 CSI 驱动状态和日志:
kubectl logs -n kube-system--tail=100
5.2 挂载失败
5.2.1 现象描述
Pod 处于 ContainerCreating 状态,describe 显示挂载卷失败。
kubectl describe pod-n | grep -A10 "Volumes"
Events 中可能显示:
Warning FailedMount 2m ago kubelet MountVolume.SetUp failed for volume "pvc-xxx" : rpc error: code = Internal desc = could not mount disk: Format disk: exit status 1
5.2.2 排查步骤
第一步:在节点上检查挂载状态
# 查看当前挂载的 PVC mount | grep pvc # 查看 kubelet 日志 journalctl -u kubelet --no-pager | grep -E "MountVolume|FailedMount" | tail -50
第二步:检查文件系统
# 查看磁盘分区 lsblk fdisk -l df -h
第三步:检查 CSI 日志
kubectl logs -n kube-system--tail=100
5.2.3 修复方案
挂载失败通常需要管理员介入。可能的操作:
重新格式化存储卷(数据会丢失,慎用)
检查存储后端健康状态
重建 Pod(可能仍会失败)
六、资源与配额问题
6.1 OOMKilled
6.1.1 现象描述
Pod 被杀死,退出码为 137(SIGKILL),Reason 为 OOMKilled。
kubectl get pod-n NAME READY STATUS RESTARTS AGE my-app-5d8f9c6b4-x7r2k 0/1 OOMKilled 1 5m
6.1.2 排查步骤
第一步:确认 OOMKilled 状态
kubectl describe pod-n | grep -E "Last State|Reason|Exit Code"
Last State: Terminated Reason: OOMKilled Exit Code: 137
第二步:检查 Pod 资源限制配置
kubectl get pod-n -o jsonpath='{.spec.containers[*].resources.limits.memory}'
第三步:查看节点内存状态
kubectl top nodes free -h
如果节点内存本身就很紧张,Pod 很容易被 OOMKill。
第四步:分析应用内存使用
kubectl exec -it-n -- /bin/sh # 在容器内查看进程内存使用 ps aux --sort=-%mem | head -10 cat /proc/meminfo
6.1.3 修复方案
方案一:增加内存限制
kubectl patch deployment-n -p '{"spec":{"template":{"spec":{"containers":[{"name":" ","resources":{"limits":{"memory":"1Gi"}}}]}}}}'
方案二:优化应用内存使用
Java 应用(JVM 堆内存设置过大):
env: - name: JAVA_OPTS value: "-Xmx512m -Xms256m"
Go 应用(内存限制和实际使用不匹配):
确认 Go 运行时 GOGC 参数是否合理
确认是否有内存泄漏
方案三:增加节点内存或扩容
6.1.4 验证方式
kubectl logs-n --previous kubectl top pod -n
确认 Pod 不再被 OOMKilled,内存使用稳定在限制值以下。
6.2 ResourceQuota 和 LimitRange
6.2.1 ResourceQuota 超限
ResourceQuota 限制 Namespace 的资源总量,超限后新 Pod 无法创建。
排查方法:
kubectl describe resourcequota -nkubectl get resourcequota -n -o yaml
输出中会显示各资源的使用量和限制量:
ResourceQuota Namespaces Status: Pods: 10/20 (80% used)
如果 pods 达到 20/20,新 Pod 无法创建。
修复方案:删除不需要的 Pod 或申请增加 ResourceQuota:
kubectl patch resourcequota-n -p '{"spec":{"hard":{"pods":"50"}}}'
6.2.2 LimitRange 超限
LimitRange 为 Namespace 内的 Pod 设置默认和最大的资源限制。
排查方法:
kubectl describe limitrange -n
如果 Pod 没有设置 resources.limits,LimitRange 会设置默认值。如果 Pod 请求的资源超过 LimitRange 的 max 值,Pod 无法创建。
七、认证授权与调度问题
7.1 RBAC 权限问题
7.1.1 现象描述
Pod 或 ServiceAccount 无法执行某些操作,报 "forbidden" 错误。
7.1.2 排查步骤
第一步:查看错误信息
kubectl auth can-i--as=system :
示例:
kubectl auth can-i get pods --as=systemdefault:my-sa -n default
第二步:检查 ServiceAccount
kubectl get sa-n -o yaml
第三步:检查 Role/ClusterRole 和 RoleBinding/ClusterRoleBinding
kubectl get role -nkubectl get rolebinding -n kubectl describe role -n kubectl describe rolebinding -n
7.1.3 修复方案
创建必要的 Role:
apiVersion: rbac.authorization.k8s.io/v1 kind:Role metadata: name:my-role namespace:rules: -apiGroups:[""] resources:["pods","services"] verbs:["get","list","watch"]
关联到 ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1 kind:RoleBinding metadata: name:my-rolebinding namespace:subjects: -kind:ServiceAccount name: namespace: roleRef: kind:Role name:my-role apiGroup:rbac.authorization.k8s.io
7.2 ServiceAccount 异常
7.2.1 现象描述
Pod 使用特定 ServiceAccount,但无法访问 API Server 或其他需要认证的资源。
7.2.2 排查步骤
第一步:检查 Pod 使用的 ServiceAccount
kubectl get pod-n -o jsonpath='{.spec.serviceAccountName}'
第二步:确认挂载的 token 是否有效
kubectl exec -it-n -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
第三步:用该 token 测试 API Server 访问
kubectl exec -it-n -- sh # 在 Pod 内测试 APISERVER=https://kubernetes.default.svc SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount TOKEN=$(cat ${SERVICEACCOUNT}/token) curl -sk ${APISERVER}/api --header "Authorization: Bearer ${TOKEN}"
7.3 调度失败——Taint 和 Toleration
7.3.1 现象描述
Pod 满足资源条件但不满足污点条件,无法调度到目标节点。
7.3.2 排查步骤
第一步:查看 Pod 无法调度的事件
kubectl describe pod-n | grep -E "Taint| Tolerat"
第二步:查看节点污点
kubectl get node-o jsonpath='{.spec.taints}'
第三步:查看 Pod 容忍
kubectl get pod-n -o jsonpath='{.spec.tolerations}'
7.3.3 常见污点类型
node.kubernetes.io/not-ready:NoExecute——节点未就绪
node.kubernetes.io/unreachable:NoExecute——节点不可达
node.cloudprovider.com/unmanaged:NoSchedule——云节点初始化未完成
node-role.kubernetes.io/control-plane:NoSchedule——控制平面节点
7.3.4 修复方案
方案一:添加匹配的容忍
kubectl patch deployment-n -p '{"spec":{"template":{"spec":{"tolerations":[{"key":" ","operator":"Exists","effect":"NoSchedule"}]}}}}'
方案二:移除节点污点(谨慎操作)
kubectl taint node:NoSchedule-
八、生产环境排查流程
8.1 快速定位路径
遇到问题时,按以下顺序快速定位:
第一步:kubectl get pods -n确认 Pod STATUS:CrashLoopBackOff / ImagePullBackOff / Pending / Terminating / Running 第二步:kubectl describe pod -n 查看 Events 和 Conditions,得出初步判断方向 第三步:kubectl logs -n --previous 查看容器退出日志 第四步:kubectl top pod / kubectl top node 确认资源使用情况 第五步:根据状态类型走专项排查路径(见前文各节)
8.2 分层排查法
第一层:集群层
# 查看所有节点状态 kubectl get nodes # 查看所有命名空间 kubectl get namespaces # 查看集群级别事件 kubectl get events --all-namespaces --sort-by='.lastTimestamp'
第二层:网络层
# 查看 Service 和 Endpoints kubectl get svc,endpoints -n# 查看 NetworkPolicy kubectl get networkpolicy -n # 从 Pod 内测试网络连通性 kubectl exec -it -n -- ping/curl/nslookup
第三层:存储层
# 查看 PVC 和 PV kubectl get pvc,pv -n# 查看 StorageClass kubectl get storageclass
第四层:应用层
# 查看 Pod 详细配置 kubectl get pod-n -o yaml # 查看应用日志 kubectl logs -n --tail=200 -f # 进入容器内部 kubectl exec -it -n -- /bin/sh
8.3 常用 kubectl 调试技巧
# 查看资源当前状态和期望状态的差异 kubectl diff -f# 实时观察资源变化 watch kubectl get pods -n # 查看资源被谁创建(帮助定位异常配置来源) kubectl get pod -n -o jsonpath='{.metadata.ownerReferences}' # 查看 Pod 的所有标签 kubectl get pod -n --show-labels # 按标签筛选 Pod kubectl get pods -n -l 'app=myapp,tier=frontend' # 查看资源历史修改(如果启用了审计日志) kubectl rollout history deployment -n # 回滚到上一个版本 kubectl rollout undo deployment -n
九、最佳实践
9.1 日志与监控
集中日志收集:确保所有 Pod 的日志统一收集到日志平台(ELK、Loki、Graylog)。不要依赖 kubectl logs 排查生产问题。
# 示例:使用 Fluentd Bit 收集日志 apiVersion: v1 kind: ConfigMap metadata: name: fluent-bit-config namespace: kube-system data: fluent-bit.conf: | [SERVICE] Flush 5 Log_Level info Daemon off [INPUT] Name tail Path /var/log/containers/*.log Parser docker Tag kube.* [OUTPUT] Name es Match kube.* Host elasticsearch.logging.svc Port 9200
监控告警:部署 Prometheus + Grafana 监控集群和 Pod 资源使用。关键告警:
Node NotReady / DiskPressure / MemoryPressure
Pod CrashLoopBackOff / OOMKilled
PVC Pending 超过 5 分钟
Pod 重启次数超过阈值
CPU/内存使用率持续高于 80%
健康检查配置:合理配置 livenessProbe 和 readinessProbe:
livenessProbe: httpGet: path:/healthz port:8080 initialDelaySeconds:30 periodSeconds:10 failureThreshold:3 readinessProbe: httpGet: path:/ready port:8080 initialDelaySeconds:5 periodSeconds:5 failureThreshold:3
livenessProbe 用于判断容器是否需要重启,readinessProbe 用于判断 Pod 是否应该接收流量。如果 livenessProbe 配置过短,频繁重启会导致业务中断。
9.2 资源配额设计
命名空间级别资源约束:为每个命名空间设置 ResourceQuota 和 LimitRange。
apiVersion: v1 kind:ResourceQuota metadata: name:default-quota namespace:spec: hard: requests.cpu:"10" requests.memory:20Gi limits.cpu:"20" limits.memory:40Gi pods:"50"
Pod 资源请求与限制:为每个容器设置合理的 requests 和 limits。
requests:调度依据,保证 Pod 调度的公平性
limits:资源上限,防止单个容器耗尽节点资源
resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "500m"
LimitRange 默认值:如果某些 Pod 没有设置资源限制,LimitRange 提供默认值:
apiVersion: v1 kind:LimitRange metadata: name:default-limit namespace:spec: limits: -type:Container default: memory:512Mi cpu:200m defaultRequest: memory:256Mi cpu:100m max: memory:2Gi cpu:"1"
9.3 灾备与回滚
资源配置版本管理:所有 Kubernetes 资源配置都应该存储在 Git 仓库中(GitOps 实践)。
Deployment 回滚:
# 查看历史版本 kubectl rollout history deployment-n # 回滚到上一个版本 kubectl rollout undo deployment -n # 回滚到指定版本 kubectl rollout undo deployment -n --to-revision=
StatefulSet 的滚动更新策略:StatefulSet 的更新需要谨慎处理,有序删除、有序创建:
spec: updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 1
数据备份:有状态应用必须配置定期备份策略。MySQL、Redis、MongoDB 等数据库的备份不应依赖 Kubernetes 自身,应使用外部备份工具。
9.4 生产操作安全规范
操作前必查清单:
影响范围确认:操作会影响哪些 Pod、哪些用户、哪些业务?
配置备份:kubectl get
回滚方案:准备好回滚命令
执行窗口:生产环境变更在业务低峰期执行
通知相关方:提前通知业务方和值班人员
审批流程:符合企业变更管理流程
高风险操作:
删除 Namespace(不可逆)
修改 RBAC 权限(可能导致集群管理权限丢失)
删除 StorageClass(可能导致 PV 无法恢复)
修改 etcd 数据(可能导致集群不可用)
大规模删除 Pod(可能导致服务中断)
验证流程:
操作前:确认服务当前状态、基线指标
操作中:观察 Pod 状态变化、错误日志
操作后:确认服务恢复、指标正常、业务连通
十、总结
Kubernetes 生产环境的故障排查,核心在于系统化思维和分层定位。从 Node 状态到 Pod 状态,从网络连通性到存储挂载,从资源配额到权限配置,每一层都有可能出现故障点。
常见问题的快速定位表:
| 现象 | 第一步排查命令 | 常见原因 |
|---|---|---|
| CrashLoopBackOff | kubectl logs --previous | 应用配置错误、依赖不可达、OOM |
| ImagePullBackOff | kubectl describe pod 事件 | 镜像不存在、认证失败、网络不通 |
| Pending | kubectl describe pod 事件 | 资源不足、污点不匹配、PVC Pending |
| Terminating 卡死 | kubectl get pod -o yaml finalizers | 挂载卡死、Finalizers 引用缺失 |
| NotReady | kubectl describe node Conditions | 磁盘满、内存满、网络异常 |
| Endpoints 为空 | kubectl get svc -o jsonpath Selector | 标签不匹配、Pod 未运行 |
| DNS 解析失败 | kubectl logs -n kube-system coredns | CoreDNS 异常、NetworkPolicy 阻断 |
| PVC Pending | kubectl describe pvc 事件 | StorageClass 不存在、CSI 异常 |
最重要的几条经验:
永远先看状态和事件,再看日志。kubectl describe 的输出往往已经足够定位方向。
生产操作前必须备份配置,保留回滚能力。Kubernetes 的声明式 API 使得配置回滚非常容易。
不要轻易重启 Pod 或 Node,这会丢失现场。优先调查根因。
资源配置要合理——requests 保证调度公平性,limits 防止资源耗尽,两者缺一不可。
监控和日志是运维的根基。没有监控,故障就不知道;没有日志,排查就无从下手。
故障排查能力是运维工程师最核心的技能之一。排查得快不快、准不准,取决于对 Kubernetes 各组件协作关系理解的深度。希望本文提供的排查路径、关键命令和修复方案,能够帮助初中级运维工程师在实际工作中快速定位问题、解决问题,在生产环境中更加从容。
全部0条评论
快来发表一下你的评论吧 !