首页 » K8s » 第11章 真实运维常见问题与处理手册

第11章 真实运维常见问题与处理手册

 

本章目录(点击跳转):

本章是全书的"急救手册"。内容整理自社区和一线运维的高频故障总结,按 集群级 → 节点级 → 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 排障总心法(最后压轴)

出问题时保持四个习惯,基本不会慌:

  1. 先备份再动手:要动 etcd/存储/集群配置之前,先快照。
  2. 从症状倒推,不要猜:get → describe → logs 的证据链走到底。
  3. 一次只改一个变量:改了 A 没好,马上回滚 A 再试 B,别叠加。
  4. 留好"逃生门":知道怎么 drain 节点、怎么回滚发布、怎么从快照恢复集群,这三件事会了,99% 的故障都不致命。

全书完。真正学会 K8s 的标志不是背下所有命令,而是出问题时你能在 10 分钟内定位到方向——这本手册就是你的第一反应手册。

原文链接:第11章 真实运维常见问题与处理手册,转载请注明来源!

赞 0