本章目录(点击跳转):
- 11.1 集群级问题
- 11.1.1 证书过期(最经典的生产事故)
- 11.1.2 etcd 出问题(集群的"心脏")
- 11.1.3 API Server 响应慢 / 集群整体卡顿
- 11.1.4 集群升级
- 11.2 节点级问题
- 11.2.1 Node NotReady(节点失联)
- 11.2.2 节点磁盘满(出现频率极高)
- 11.2.3 节点资源不够,Pod 一直 Pending
- 11.2.4 Pod 被 Evicted(驱逐)
- 11.3 Pod 级问题(按出现频率排)
- 11.3.1 ImagePullBackOff / ErrImagePull
- 11.3.2 CrashLoopBackOff 的"五连问"
- 11.3.3 OOMKilled
- 11.3.4 Pod 卡在 Terminating
- 11.3.5 滚动更新卡住(新 Pod 起不来/旧 Pod 不删)
- 11.3.6 探针导致的"灵异重启"
- 11.4 网络问题
- 11.4.1 CoreDNS 挂了(全集群解析失败)
- 11.4.2 Service 通了但 502/504(Ingress 后端问题)
- 11.4.3 Ingress TLS 证书过期(443 打不开)
- 11.4.4 跨节点访问不通(CNI 问题)
- 11.5 存储问题
- 11.5.1 PVC 一直 Pending
- 11.5.2 容器里写文件报错
no space left,但节点 df 看着有空 - 11.5.3 删了 StatefulSet/Pod,数据没了?
- 11.6 配置与权限问题
- 11.6.1
Forbidden(权限不足) - 11.6.2 ConfigMap 改完不生效
- 11.6.3 配额超限(exceeded quota)
- 11.7 日常维护清单(每月必做)
- 11.8 排障总心法(最后压轴)
本章是全书的"急救手册"。内容整理自社区和一线运维的高频故障总结,按 集群级 → 节点级 → Pod 级 → 网络 → 存储 → 配置权限 → 日常维护 分类。每个问题按 症状 → 原因 → 处理 三段写,建议收藏,出问题时按目录翻。
11.1 集群级问题
11.1.1 证书过期(最经典的生产事故)
症状(出现任意一条都先怀疑证书):
kubectl 报:x509: certificate has expired, not valid before ...
curl https://<apiserver>:6443 报证书错误
kubelet 日志:x509: certificate signed by unknown authority
Node 突然 NotReady,kubelet 日志全是 TLS 错误
背景:kubeadm 默认生成的证书有效期 1 年,包括:
- apiserver 的 serving 证书
- apiserver 访问 etcd 的客户端证书
- kubelet 的 serving / client 证书
- controller-manager、scheduler 的证书
到期不续,集群直接瘫痪(apiserver 无法对外服务、etcd 拒绝连接)。
处理(kubeadm 集群):
# 1) 在控制面节点上,统一续所有证书
sudo kubeadm certs renew all
# 2) 重启静态 Pod 让新证书生效(每个控制面节点都要做)
sudo systemctl restart kubelet
# 3) 如果之前 kubectl 也报过期(客户端证书),单独续:
kubectl certificate renew
# 4) 验证
kubectl get nodes
kubectl get pods -A
如果证书已经全过期导致 kubectl 完全不可用(先手动续 kubectl 证书):
# 找到过期最晚的 CA,给 kubectl 签一个新客户端证书(简化示意)
# 实际操作:在控制面节点上先 kubeadm certs renew all,
# 然后从 /etc/kubernetes/pki 拿新证书更新本地 kubeconfig 中的 CA,
# 再 kubectl certificate renew
最佳实践(强烈建议):
- 日历/监控提醒:每年到期前 1 个月处理,别等挂了再救火;
- 用 cert-manager 接管集群证书,自动续期(云上托管集群一般由平台代管);
- 监控里加一条告警:
apiserver 证书剩余有效期 < 30 天(Prometheus 有对应 exporter 指标)。
11.1.2 etcd 出问题(集群的"心脏")
etcd 挂了 = 集群瘫痪。常见三种:
**① etcd 报 db quota exceeded(数据量超默认 2GB)**
# 症状:apiserver 报错 etcdserver: mvcc: database space exceeded
# 集群还能看,但创建/更新资源全部失败
# 1) 压缩(清理历史版本,不删数据)
ETCDCTL_API=3 etcdctl endpoint compaction
# 2) 碎片整理(在控制面节点上,对本地 etcd)
ETCDCTL_API=3 etcdctl defrag --cluster
# 3) 长期方案:调大 quota(kubeadm 集群)
# 编辑 /etc/kubernetes/manifests/etcd.yaml 的 command 参数:
# --quota-backend-bytes=8589934592 (8GB)
# 然后 systemctl restart kubelet
② etcd 进程挂了 / 数据异常
# 1) 看 etcd 状态(控制面节点上)
sudo systemctl status etcd
ETCDCTL_API=3 etcdctl endpoint status --write-out=table
ETCDCTL_API=3 etcdctl endpoint health
# 2) 先做快照备份再动别的(重要!)
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup-$(date +%F).db
# 多节点集群加:
# --endpoints=https://127.0.0.1:2379 \
# --cacert=/etc/kubernetes/pki/etcd/ca.crt \
# --cert=/etc/kubernetes/pki/etcd/server.crt \
# --key=/etc/kubernetes/pki/etcd/server.key
# 3) 最坏情况:用快照恢复(kubeadm 官方流程)
# kubeadm etcd snapshot restore <快照文件> --cert-dir /tmp/restored-certs
# 恢复后集群是新 etcd,节点要重新 join(流程较长,动手前查官方文档)
③ etcd 所在磁盘满了 → 见 11.2.2 磁盘满。
11.1.3 API Server 响应慢 / 集群整体卡顿
症状:kubectl 命令偶尔卡 10s+,watch 丢事件,controller 延迟高。
常见原因与排查:
# 1) etcd 是不是瓶颈(最常见)
ETCDCTL_API=3 etcdctl endpoint status --write-out=table # DB Size
ETCDCTL_API=3 etcdctl endpoint latency
# 2) 是不是某人在疯狂 list 大资源(比如 list 全集群 pods)
# apiserver 日志里大量 List /v1/pods 请求;
# 处理:让该客户端改用分页(limit/continue)或按 ns 过滤
# 3) 事件太多(apiserver 事件日志爆)
kubectl get events -A | wc -l
# 大量 CrashLoop 的 Pod 会疯狂产生事件,先消灭源头
# 4) 控制面节点 CPU/内存是否不足(top / kubectl top node)
11.1.4 集群升级
原则:一次最多升一个大版本(如 1.34 → 1.35),先升控制面再逐台升节点;升级前全量备份(etcd + Velero)。
# 升级前
kubectl get version
# 备份 etcd 快照(11.1.2 的命令)
# kubeadm 集群升级(示意)
sudo kubeadm upgrade plan v1.35.0 # 先做计划
sudo kubeadm upgrade apply v1.35.0 # 控制面
# 每个工作节点:
sudo kubeadm upgrade node
sudo systemctl restart kubelet
# 最后:kubectl get cs、kubectl get nodes 全绿
# 升级卡住回滚:kubeadm 不支持一键回滚,靠升级前的备份恢复
11.2 节点级问题
11.2.1 Node NotReady(节点失联)
症状:kubectl get nodes 某节点 NotReady。
排查顺序(登录节点执行):
# 1) kubelet 活着吗?
sudo systemctl status kubelet
journalctl -u kubelet -n 100 --no-pager # 看日志找根因
# 2) kubelet 和网络通吗?(NotReady 很多时候是网络断了)
ping <apiserver-ip>
curl -k https://<apiserver>:6443/healthz
# 3) 资源是不是爆了?
free -h # 内存
df -h # 磁盘
dmesg -T | tail -50 # 有没有 OOM killer / 内核报错
# 4) CNI 是否正常?(Pod 网络挂了也会导致 NotReady)
crictl ps | grep -E "calico|flannel|cilium"
常见根因:
| 根因 | 处理 |
|---|---|
| kubelet 挂了 | systemctl restart kubelet,日志查原因 |
| 磁盘满 | 见 11.2.2 |
| 内存不足被 OOM | 加内存/迁走负载,调 eviction 阈值 |
| 网络/时间问题 | 修网络;校时(时钟偏差大也会导致证书验证失败):timedatectl + NTP |
| 机器真坏了 | kubectl cordon <node> 隔离,迁移工作负载,换机器 |
节点下线标准流程(缩容/换机必背):
# 1) 标记不可调度(不再调度新 Pod)
kubectl cordon <node>
# 2) 驱逐节点上的 Pod(Deployment 会在别处重建)
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
# 3) 从集群移除(kubeadm 集群,在节点上执行)
sudo kubeadm reset
# 控制面节点移除更复杂,参考 kubeadm 官方 "remove control plane node" 流程
# 重新上线:kubectl uncordon <node>
11.2.2 节点磁盘满(出现频率极高)
症状:节点 DiskPressure: True,Pod 被驱逐,kubelet 报错 no space left on device。
先定位是什么占了:
# 节点上:
df -h # 哪个分区满了
du -sh /var/lib/containerd /var/lib/docker /var/log 2>/dev/null | sort -h
du -xh --max-depth=2 / | sort -rh | head -20 # 全局找大目录
大头通常是这三处:
# 1) 无用镜像(最大头)
crictl images # 看镜像列表
crictl rmi <镜像名> # 删无用镜像
# 或让 kubelet 自己 GC:确认 imageGCHighThresholdPercent 配置(默认 85%)
# 2) 已退出容器占的空间
crictl ps -a | grep Exited
crictl rm <容器id>
# 3) 日志(journal + 容器日志)
journalctl --vacuum-size=500M
# 容器日志限制:kubelet 的 containerLogMaxSize(默认 10Mi)
# 调 /var/lib/kubelet/config_kubelet.conf:
# containerLogMaxSize: "50Mi"
# containerLogMaxFiles: 3
长期预防:
- 监控节点磁盘使用率 > 80% 告警;
- 定期清理任务(CronJob 或脚本):删 N 天前的无用镜像/日志;
- 给系统盘留足余量(建议系统盘 ≥ 50G)。
11.2.3 节点资源不够,Pod 一直 Pending
症状:describe pod 事件里有 0/N nodes are available: 3 Insufficient cpu。
# 1) 看集群剩余资源
kubectl top nodes
kubectl describe nodes | grep -A3 "Allocated resources"
# 2) 处理思路(按优先级):
# a) 删掉不用的资源(僵尸 Deployment、没缩容的测试应用)
# b) 调小该应用的 requests(11.2.4)
# c) 扩节点
# d) 把 requests 设得过高的 Pod 迁走
11.2.4 Pod 被 Evicted(驱逐)
症状:Pod 状态 Evicted,事件 The node was low on resource: [Memory]。
# 看是谁把节点内存吃光了
kubectl top pods -n <ns> --sort-by=memory
# 处理:调大节点内存 / 调小大户应用的 requests 和 limits /
# 调整 kubelet 驱逐阈值(eviction-hard,默认 memory.available<100Mi)
注意:被驱逐的是超 limit 或 requests 总和超出节点可用的 Pod,不一定是"坏"的 Pod。
11.3 Pod 级问题(按出现频率排)
11.3.1 ImagePullBackOff / ErrImagePull
# 1) 先确认镜像名和 tag 真的存在
docker pull <镜像> # 本机试拉
# 2) 私有仓库:凭证问题
kubectl get secret | grep regcred
# secret 过期/密码改了 → 重建 secret(第 7 章)
# 检查 imagePullSecrets 是否配在正确的 ns / SA 上
# 3) 节点到 registry 的网络
# 节点上:curl -I https://registry.example.com/v2/
# 公司内网:配置镜像加速/代理(kubelet 的 registry 镜像配置)
# 4) 拉取超时(大镜像):看 kubelet 日志;考虑预热(DaemonSet 提前 pull)
11.3.2 CrashLoopBackOff 的"五连问"
拿到崩溃日志后,按这个清单过一遍:
1. 配置对不对? env/ConfigMap/Secret 的 key 有没有拼错
2. 依赖在不在? 数据库/中间件 DNS 通不通、端口通不通
3. 端口冲突吗? 容器内已有进程占用
4. 资源够吗? 启动即 OOM(limits 太小)
5. 版本兼容吗? 镜像升级后配置格式变了(很常见!)
kubectl logs <pod> -p --tail=200 # 崩溃现场
kubectl describe pod <pod> | grep -B2 -A8 "Last State"
11.3.3 OOMKilled
# 症状:Last State: Terminated, Reason: OOMKilled, Exit Code: 137
# 1) 看真实内存水位(不是看 limit!)
kubectl top pod <pod>
# 2) 处理:
# - 水位长期贴 limit → 调大 limits(同时看是否内存泄漏)
# - 是泄漏 → 应用侧修;临时加 limit 争取时间
# - Java 应用特别注意:JVM 堆大小要和 container limit 匹配(-XX:MaxRAMPercentage=75)
11.3.4 Pod 卡在 Terminating
# 1) 先看为什么删不掉
kubectl describe pod <pod>
# 常见:finalizer 没清理完 / 挂载的卷卸不掉 / 节点失联
# 2) 优雅等待超时后强删(先确认业务无影响)
kubectl delete pod <pod> --grace-period=0 --force
# 3) 节点失联导致的僵尸 Pod:
kubectl get pods --field-selector=status.phase=Running -o wide
# 确认节点已坏后:kubectl drain 或强删,再处理节点
11.3.5 滚动更新卡住(新 Pod 起不来/旧 Pod 不删)
kubectl rollout status deployment web # 卡住时看提示
kubectl get pods -l app=web -o wide
# 逐个 describe 没就绪的新 Pod:多半是
# - readiness 探针不过(新镜像健康检查路径变了!)
# - 新镜像拉不下来
# - PDB 限制(minAvailable 太大)
# - 资源不足(新副本起不来)
# 处理完根因后:
kubectl rollout resume deployment web # 如果是 pause 状态
# 彻底放弃本次升级:
kubectl rollout undo deployment web
11.3.6 探针导致的"灵异重启"
应用明明活着却被反复重启,九成是探针问题:
1. 健康检查接口慢(> timeoutSeconds)→ 调大 timeout
2. 接口偶尔 5xx(依赖抖动)→ 调大 failureThreshold
3. 启动慢(大应用 30s+)→ 加 startupProbe
4. 探针路径写错(/health 404)→ 修路径
5. liveness 依赖了外部服务 → 反模式!liveness 只查自己,
外部依赖放 readiness
11.4 网络问题
11.4.1 CoreDNS 挂了(全集群解析失败)
# 症状:所有 Pod 里 nslookup 超时,但 IP 直连通
kubectl get pods -n kube-system -l k8s-app=kube-dns
# CoreDNS Pod 挂了 → describe/logs 找原因(常见:节点资源、镜像拉取)
# 快速临时救火:手工起一个 coredns 替换
kubectl run coredns-tmp -n kube-system --image=coredns/coredns:1.11.1 \
--overrides='{"spec":{"containers":[{"name":"coredns","image":"coredns/coredns:1.11.1","command":["coredns","-conf","/etc/coredns/Corefile"],"volumeMounts":[{"name":"config-volume","mountPath":"/etc/coredns","readOnly":true}]}],"volumes":[{"name":"config-volume","configMap":{"name":"coredns","items":[{"key":"Corefile","path":"Corefile"}]}}]}}'
11.4.2 Service 通了但 502/504(Ingress 后端问题)
1. kubectl get endpoints <svc> → 空的?selector 不匹配 / Pod 没就绪
2. Pod 里实际监听端口 ≠ targetPort → 改 Service 或应用
3. 后端应用真的 5xx → 看应用日志(可能是应用 bug 或依赖挂)
4. Ingress controller 自身 OOM/挂了 → kubectl get pods -n ingress
11.4.3 Ingress TLS 证书过期(443 打不开)
症状:浏览器"您的连接不是私密连接",curl -vI https://域名 报 certificate has expired。
# 1) 找到 Ingress 用的 Secret
kubectl get ingress -A -o jsonpath='{range .items[*]}{.metadata.namespace} {.spec.tls[0].secretName}{"\n"}{end}'
# 2) 看证书有效期
kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates
# 3) 换证书(手动方式)
# 拿到新证书和 key 后:
kubectl create secret tls myapp-tls --cert=new.crt --key=new.key \
--dry-run=client -o yaml | kubectl apply -f -
# (同名字 secret 直接更新,Ingress 会自动加载新证书)
# 4) 长期方案:cert-manager + Let's Encrypt 自动续期
# 申请 Certificate 资源,自动申请/续期/更新 secret
⚠️ 注意区分两种证书:Ingress 的站点证书(对用户的 HTTPS,11.4.3)和 集群内部证书(1 年期,11.1.1),过期时间完全不同,都容易踩。
11.4.4 跨节点访问不通(CNI 问题)
1. 同节点 Pod 互通、跨节点不通 → CNI 问题
看 CNI Pod(calico/flannel/cilium)状态和日志
2. 节点间网络本身不通 → 安全组/防火墙没开 CNI 需要的端口和协议
(calico BGP、flannel VXLAN UDP 8472 等,查对应文档)
3. 云厂商环境:确认开了"内网互通",子网配置正确
11.5 存储问题
11.5.1 PVC 一直 Pending
kubectl describe pvc <name>
# Events 里写得很明白,常见:
# - no persistent volumes available for claim(没有合适 PV)
# - storageclass "xxx" not found(SC 写错/不存在)
# - accessModes 不匹配(要 RWX 但只有 RWO 的存储)
11.5.2 容器里写文件报错 no space left,但节点 df 看着有空
常见原因:
1. 是 PVC 对应的盘满了(不是系统盘):
kubectl exec <pod> -- df -h /data
2. minikube/本地环境:local-path 的目录满了(/minikube 或 /tmp)
3. 云盘没扩容:云盘 PVC 在线扩容要 SC 支持 allowVolumeExpansion
11.5.3 删了 StatefulSet/Pod,数据没了?
先别慌,按顺序确认:
1. PVC 还在不在?kubectl get pvc -A
2. reclaimPolicy 是什么?Delete 的话 PVC 一删数据就没了
3. 云盘/本地 PV 的底层卷还在吗?(云平台控制台看)
4. 有备份吗?(10.2.4 说过:没演练的备份等于没有)
预防:重要存储 SC 设 reclaimPolicy: Retain + 定期备份
11.6 配置与权限问题
11.6.1 Forbidden(权限不足)
# 1) 确认当前身份
kubectl whoami # 或 kubectl config view --minimize
# 2) 具体缺什么权限
kubectl auth can-i <verb> <resource> -n <ns>
# 3) 找管理员补 RoleBinding(第 8 章)
# 4) 如果是 Pod 内程序报 forbidden:
kubectl get sa -n <ns>
kubectl auth can-i list pods --as=system:serviceaccount:<ns>:<sa-name> -n <ns>
11.6.2 ConfigMap 改完不生效
1. env 方式注入 → 必须重启 Pod:kubectl rollout restart deployment <name>
2. 文件挂载方式 → 有最多 1 分钟同步延迟,且应用要自己监听变化
3. 改错了 ns / 改错了 key → kubectl get cm <name> -o yaml 核对
4. Deployment 里引用的 cm 名字写错 → Pod 起不来或变量为空
11.6.3 配额超限(exceeded quota)
kubectl get resourcequota -n <ns>
# 报错会写明超的是哪一项(pods 数 / cpu / memory / pvc 数)
# 处理:清理无用资源,或找管理员调大 quota
11.7 日常维护清单(每月必做)
把下面这张表贴到团队墙上,能挡住 80% 的"半夜被叫醒":
| 周期 | 事项 | 命令/工具 |
|---|---|---|
| 每日 | 看节点是否 Ready、有无 Warning 事件 | kubectl get nodes、kubectl get events -A --field-selector type=Warning |
| 每日 | 资源水位(CPU/内存/磁盘) | kubectl top nodes、监控大盘 |
| 每周 | 镜像/日志清理、僵尸资源清理 | crictl rmi、kubectl get deploy -A 核对 |
| 每月 | etcd 压缩 + 碎片整理 + 快照备份 | 11.1.2 的命令 |
| 每季度 | 演练一次备份恢复(etcd/Velero) | 恢复流程实操 |
| 每年 | 集群证书续期(到期前 1 个月) | kubeadm certs renew all |
| 持续 | 版本跟进(落后 1-2 个版本内) | kubeadm upgrade plan |
监控告警最低配置(别裸奔):
1. Node NotReady 告警
2. 节点磁盘 > 80% / 内存可用 < 10%
3. Pod 长期 Pending / CrashLoop 计数
4. etcd DB Size > 1.5GB
5. apiserver 证书 / Ingress 站点证书剩余有效期 < 30 天
6. PVC 使用率 > 80%
11.8 排障总心法(最后压轴)
出问题时保持四个习惯,基本不会慌:
- 先备份再动手:要动 etcd/存储/集群配置之前,先快照。
- 从症状倒推,不要猜:
get → describe → logs的证据链走到底。 - 一次只改一个变量:改了 A 没好,马上回滚 A 再试 B,别叠加。
- 留好"逃生门":知道怎么 drain 节点、怎么回滚发布、怎么从快照恢复集群,这三件事会了,99% 的故障都不致命。
全书完。真正学会 K8s 的标志不是背下所有命令,而是出问题时你能在 10 分钟内定位到方向——这本手册就是你的第一反应手册。
原文链接:第11章 真实运维常见问题与处理手册,转载请注明来源!
