Kubernetes生产环境常见问题与排查命令总结

描述

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 -n 
NAME                        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 -n 
NAME                        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 pull 
docker 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 -n 
NAME                        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 -n 
kubectl describe pod  -n  | grep -A10 "Volumes"

 

如果 PVC 处于 Pending,Pod 会等待存储绑定:

 

kubectl get pvc -n 
NAME                        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 -n 
NAME                        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         NotReady           60d   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 -n 
kubectl 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 -n 
kubectl 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 -n 
kubectl describe ingress  -n 

 

第三步:检查 Ingress Class

确认 Ingress 使用的是集群中已部署的 Ingress Class:

 

kubectl get ingressclass
kubectl get ingress  -n  -o jsonpath='{.spec.ingressClassName}'

 

第四步:检查后端 Service 和 Endpoints

 

kubectl get svc -n 
kubectl 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 -n 
NAME                        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 -n 
kubectl 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 -n 
kubectl 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 -n -o yaml > backup.yaml

回滚方案:准备好回滚命令

执行窗口:生产环境变更在业务低峰期执行

通知相关方:提前通知业务方和值班人员

审批流程:符合企业变更管理流程

高风险操作:

删除 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 各组件协作关系理解的深度。希望本文提供的排查路径、关键命令和修复方案,能够帮助初中级运维工程师在实际工作中快速定位问题、解决问题,在生产环境中更加从容。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分