Kubernetes集群排查实战:从控制面到Node的组件、配置与运维指南
Kubernetes 集群排查起来最让人上火的场景不是业务 YAML 写错而是整条链路里的任何一个组件掉了队你都不知道该从哪里看起apiserver 还能不能接kubelet 有没有在向控制面报心跳Node 上的 iptables 规则到底是谁刷进去的这些问题绕不开一个基础——把 Master现在更常叫控制面与 Node 两侧的组件、服务、配置文件彻底弄清楚。这篇文章我把实际交付集群时最常被问到、也最容易被忽略的点串一遍适合刚接触 K8s 的运维同学也适合那些已经能部署集群、但一出问题就靠重启解决的“伪熟手”。先从整体架构说起再逐个拆组件然后落到配置文件和 systemd 服务最后给一段我自己常用的排查路径。1. 集群整体架构与控制面设计思路1.1 控制面与工作节点的分工逻辑Kubernetes 把集群从逻辑上切成两部分。控制面负责“决策”工作节点负责“执行”。这句话听起来简单但我在实际运维中见过很多人在排查时把两者的职责混在一起导致方向完全跑偏。控制面由 apiserver、etcd、controller-manager、scheduler 这几个核心组件构成它们的任务是维护集群的期望状态、分配资源、循环修正实际状态与期望状态之间的偏差。Node 侧则是 kubelet、kube-proxy、容器运行时这些执行者负责接收控制面下发的任务把 Pod 真正跑起来并持续回报状态。这个设计有一个很关键的取舍所有状态都集中存放在 etcd所有读写都经 apiserver 统一入口Node 上的组件不需要互相通信也不直接连 etcd。好处是状态一致性强、审计与权限控制可以收敛在一个位置代价是 apiserver 和 etcd 变成绝对的单点瓶颈一旦它们出问题整个集群的“神经系统”就瘫痪。运维的重心因此很明确控制面要稳、要快Node 侧要可控、要可观测。用生活化的类比来说控制面是公司的管理层和人事部Node 是一线车间。管理层定目标、排计划、做考核车间只管干活、报进度。如果车间自己乱改计划管理层根本不知情那整个公司就失控了。Kubernetes 就是靠这种“声明式状态 持续对账”的机制避免了失控这也是为什么它比一堆脚本拼起来的容器管理方案稳定得多。1.2 组件间通信路径与请求流转理解集群里一条请求的完整流转路径是排错的基本功。最常见的 kubectl get pods 背后完整链路是这样的kubectl 读取本地 kubeconfig拿到 apiserver 的地址和证书发起 HTTPS 请求apiserver 做认证、鉴权、准入控制然后从 etcd 读取数据或者经过 informer 缓存返回结果。但真正的关键不在于“查”而在于“监听”。控制面和 Node 侧组件都不是靠轮询工作的而是通过 apiserver 的 watch 机制维持长连接收到资源变化事件后再做相应的处理。scheduler 监听未调度的 Podcontroller-manager 里的各个 controller 监听自己负责的资源kubelet 监听分配到本节点的 Podkube-proxy 监听 Service 和 EndpointSlice。这种事件驱动模式让整个集群的响应非常快但也意味着 apiserver 必须维持大量长连接连接数管理、超时设置、证书轮换这些细节就成了日常运维逃不开的话题。我特别提醒一点所有组件之间的通信都走 TLS而且每个组件都有独立的证书或 ServiceAccount 凭据。很多人排查问题时只盯着业务日志忽略证书过期这类“慢性病”结果 apiserver 日志里全是 TLS handshake error节点侧反复重连。这个问题在后面配置和排错章节我会专门展开。1.3 为什么理解组件边界比背参数更重要我见过有人能把 kube-apiserver 的启动参数背得滚瓜烂熟集群一出问题却只会 restart 所有服务。原因就是只记住了“有什么”没理解“谁负责什么”。组件边界清晰之后排查路径几乎是机械式的Pod 一直 Pending去看 scheduler 为什么没选到节点Pod 调度了但 ContainerCreating去看 kubelet 和容器运行时Pod Running 但访问不通去看 kube-proxy 和 Service 后端整个 apiserver 变慢去看 etcd、看 apiserver 的 metrics、看连接数。这种“按职责定位问题”的思路比背任何参数都值钱。后面每一节我都会在讲组件的时候顺带说清楚这个组件“坏了会有什么现象”把知识绑定到故障场景上而不是孤立地记概念。2. Master控制面组件逐个拆解2.1 kube-apiserver一切请求的入口apiserver 是控制面里最核心、也最“忙”的组件。它对外暴露 Kubernetes API对内承担认证、鉴权、准入控制、API 聚合、数据读写等一揽子功能。整个集群里几乎所有的变更操作都要经过它所以它本质上是一个无状态网关加状态协调器的混合体——本身不存数据数据全在 etcd。部署层面apiserver 是可以水平扩展的生产环境一般至少跑两个实例前面挂负载均衡器。正因为无状态多实例之间不需要同步 session只要它们连的是同一个 etcd 就行。这里有一个经常被忽视的点apiserver 扩展后etcd 的读写压力会随之上升而且每个 apiserver 都会建立到 etcd 的 watch 连接所以 apiserver 不是想加就加的要观察 etcd 的延迟和连接数。启动参数里--secure-port默认 6443是现在唯一对外提供服务的端口老的 --insecure-port 早就被移除了。还有几个参数在实际调优时值得关注--max-requests-inflight 和 --max-mutating-requests-inflight 控制读写请求的并发上限默认值偏保守大集群遇到突发流量时可以适度调大--watch-cache 默认开启能明显降低 etcd 读压力。但我建议调整这些参数之前先看指标再动手而不是拍脑袋改大。注意apiserver 的日志级别默认是 2生产环境不建议开到 4 以上否则每个请求的详细内容都会打出来磁盘和性能都扛不住。需要排具体请求问题时可以短时间开高日志级别再关掉。2.2 etcd集群状态的唯一事实来源etcd 是 Kubernetes 的“数据库”而且是共识型的分布式存储。集群里的一切状态——节点信息、Pod 定义、Service、ConfigMap、Secret、各类 CRD 对象——都以 key-value 的形式存在这里。它采用 Raft 协议保证多节点数据一致生产环境至少要 3 个节点奇数个。etcd 对磁盘性能非常敏感写延迟直接决定 apiserver 的响应速度。我在交付环境时就遇到过因为底层存储是慢速网络盘导致 etcd 频繁出现 leader electionapiserver 间歇性不可用的情况。如果监控里看到 etcd 的 fsync 耗时异常别急着怪网络或集群流量先查磁盘。运维上etcd 的备份是优先级最高的一件事没有之一。常用的方式是 etcdctl snapshot save但要记住快照只能“定期”保底真正能不能恢复还得定期做恢复演练。我亲眼见过某团队半年没备份一次误删 namespace 之后恢复无门最后只能回退到很早的快照丢了一大批新创建的对象。恢复流程是 etcdctl snapshot restore然后重启 apiserver、controller-manager、scheduler。这个流程建议每个运维同学都至少完整演练一次。另外etcd 默认的键空间不是无限的历史版本会保留一段时间及时做压缩compact和碎片整理defrag能避免空间膨胀。如果 etcd 数据目录暴涨多半是没配 compaction 策略或者 watch 客户端没有及时消费导致历史版本积压。2.3 controller-manager 与 scheduler控制面的“大脑”与“调度员”controller-manager 实际是一个包工头里面打包了几十个小 controller比如节点控制器、副本控制器、Deployment 控制器、EndpointSlice 控制器、ServiceAccount 控制器等。它的核心机制就是“控制器循环”期望状态 vs 实际状态有偏差就调。比如 Deployment 期望 3 个副本实际只有 2 个controller 就会创建第 3 个 Pod。controller-manager 高可用部署时依赖 leader election多个实例只有一个在工作其余待命。所以你会看到它默认启动参数里有 --leader-electtrue。这里有个直觉要扭转过来apiserver 是多实例同时工作的controller-manager 却不是它是“一主多备”。如果我们错误地给 controller-manager 前面也加负载均衡转发写请求反而会出问题。正确做法是多实例直连 apiserver让它们自己通过租约选主。scheduler 负责给未调度的 Pod 找节点。它的工作分两步过滤和打分。过滤解决“能不能放”比如节点资源够不够、有没有满足 nodeSelector、容忍度是否匹配污点打分解决“放哪里更好”会综合资源余量、亲和性规则等。理解 scheduler 的日志和事件对排查 Pending 的 Pod 特别有用。我常用的排查命令是 kubectl describe pod 查看 Events 段Pending 的原因几乎都会直接写在那里比如 0/3 nodes are available: 1 Insufficient cpu, 2 node(s) had taint。大多数情况下根本不需要翻 scheduler 日志看 Events 就够了。2.4 cloud-controller-manager 与高可用部署要点cloud-controller-managerCCM是云厂商提供的控制面组件负责把集群与云平台的基础设施打通典型职责包括给 Node 打上地区/可用区标签、为 Service 分配云负载均衡器、管理节点路由。如果我们是自建裸金属集群或内网环境一般不需要 CCM直接用 kube-controller-manager 里相应的控制器即可。自建集群的高可用布局我强烈建议按这个标准来3 个控制面节点每台同时跑 apiserver、controller-manager、scheduleretcd 可以是独立的 3 节点也可以跟随控制面共存。共存模式称为 stacked etcd节点少、运维简单但控制面节点宕机时 etcd 和数据面都会受影响独立模式更稳但机器成本和复杂度都更高。小规模生产环境用 stacked 完全够规模大了再拆分。控制面前面必须有一个高可用的负载入口常见方案是 VIP keepalived或者直接用云负载均衡器。注意不要把 apiserver 的 6443 端口直接暴露到公网除非配合严格的来源 IP 白名单否则爆破风险极高。集群内部组件之间访问 apiserver一般通过固定域名如 kubernetes.default.svc或负载均衡器地址证书里的 SAN 要提前把这些地址配进去。3. Node 侧组件与服务解析3.1 kubelet节点上的核心代理kubelet 是运行在每个 Node 上的“驻场代表”它负责三件大事从 apiserver 获取分配给本节点的 Pod 清单、通过容器运行时把 Pod 拉起来、持续上报节点和 Pod 的状态。它也是节点健康状态的上报者Node 的 Ready/NotReady 状态就是它定期更新的。kubelet 通过心跳机制向控制面报告自己还活着。如果 kubelet 和 apiserver 之间的网络断开或者 kubelet 本身崩了控制面在一定时间默认 node-monitor-grace-period 40 秒后就会把 Node 标记为 NotReady并触发 NodeLifecycleController 的驱逐逻辑。注意这里有一个很多人误解的点——Node NotReady 并不会自动把上面的 Pod 调度到别处除非这些 Pod 由 DaemonSet 或 Deployment 管理且满足驱逐条件而且还要等 pod-eviction-timeout 超时。业务要有自愈能力不能指望节点挂了系统自动“搬家”。kubelet 的配置项非常多但日常最容易踩坑的是几个静态 Pod 目录 staticPodPath我后面单独讲、cgroupDriver 必须与容器运行时一致否则 kubelet 直接启动失败、maxPods 决定单节点 Pod 上限、evictionHard 决定内存/磁盘达到阈值时怎么处理。这些配置在后续的配置文件章节会展开。注意kubelet 启动失败时错误信息通常很明确比如 “failed to run Kubelet: failed to validate kubelet flags” 或 cgroup 驱动不一致。不要一上来就 reboot 节点先 journalctl -u kubelet -n 100 看一下真实报错大部分问题都能在日志里直接定位。3.2 kube-proxy 与服务负载均衡原理kube-proxy 常常被误理解为“代理”实际上在生产环境的绝大多数模式下它并不转发网络包而是把 Service 的抽象规则转译成节点上的实际转发规则。最常用的两种模式是 iptables 和 IPVS。iptables 模式下kube-proxy 为每个 Service 生成一组规则访问 ClusterIP 的流量会在内核态按规则转发到后端 Pod。规则多到一定程度时iptables 的性能和更新速度都会下降这也是很多大集群切到 IPVS 的原因。IPVS 模式在内核里维护转发表天然支持更多负载均衡算法rr、lc、sh 等规则数量再多也扛得住但依赖 ipvs 内核模块和 ipset部署时要在节点上确认模块已加载。从这里我们能推理出一个重要的排错点如果 Service 访问不通多半是 kube-proxy 生成的规则不见了或者后端 Endpoint 为空。前者看 kube-proxy 日志后者看 kubectl get endpoints。还有一个高频坑Pod 里的流量访问 ClusterIP 时如果外部流量经过 SNAT 导致回程路径错误就需要理解 externalTrafficPolicy 的 Cluster 和 Local 两种模式的区别。Local 模式保留客户端源 IP但必须确保流量打到有后端 Pod 的节点否则会丢包Cluster 模式不挑节点但会做 SNAT源 IP 会丢。3.3 容器运行时与监控数据链路Node 上真正拉起容器的不是 kubelet而是容器运行时。kubelet 通过 CRI容器运行时接口调用运行时常见的是 containerd 和 CRI-O。containerd 是当前最主流的默认选择它内部又依赖 runc 这类低层运行时来真正创建和运行容器进程。这里要说一个容易混淆的概念每个 Pod 里除了业务容器还有一个不可见的“暂停容器”pause container / sandbox。它负责持有 Pod 的网络命名空间和 PID 命名空间等基础设施业务容器启动时加入它创建好的命名空间。如果看到节点上有很多 paused 状态的容器那是正常的不要当成僵尸进程去清理。监控数据链路也是运维必须清楚的kubelet 内置的 cAdvisor 会采集节点和容器的 CPU、内存、网络、磁盘等指标metrics-server 通过 kubelet 的资源指标接口抓取这些数据供 kubectl top 和 HPA 使用。如果 kubectl top 看不到数据大概率是 metrics-server 和 kubelet 的证书、端口或聚合层配置有问题而不一定是业务容器的问题。容器日志的存储路径一般是 /var/log/pods、/var/log/containers按 Pod 和容器分目录。排查时用 kubectl logs 不行的情况下比如容器已退出可以直接去这两个目录或容器运行时的工作目录找日志文件。4. 关键配置文件与参数说明4.1 kubelet 配置文件关键项从 Kubernetes 1.14 之后官方把 kubelet 的配置逐步迁移到 YAML 格式的文件中由 --config 参数指定。以一份典型的 kubelet 配置为例apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration address: 0.0.0.0 port: 10250 staticPodPath: /etc/kubernetes/manifests cgroupDriver: systemd clusterDNS: - 10.96.0.10 clusterDomain: cluster.local maxPods: 110 evictionHard: memory.available: 100Mi nodefs.available: 10% nodefs.inodesFree: 5% registerNode: true tlsCertFile: /etc/kubernetes/pki/kubelet.crt tlsPrivateKeyFile: /etc/kubernetes/pki/kubelet.key authentication: x509: clientCAFile: /etc/kubernetes/pki/ca.crt这里最值得下功夫理解的是三处cgroupDriver 必须和容器运行时一致systemd 发行版一般都用 systemd如果 containerd 的 systemd_cgroup 为 true 而 kubelet 写的是 cgroupfskubelet 会拒启evictionHard 是一组硬性驱逐阈值达到后 kubelet 会开始回收节点上的 PodmaxPods 不只是一个数字它还牵扯到节点需要多大的网段、多少 IP 资源以及 apiserver 侧 watch 的压力。我遇到过不止一次因为 maxPods 调大、但 CNI 插件没有分配足够的可用 IP 池导致后面新 Pod 拿不到 IP、一直 ContainerCreating 的情况。所以调 maxPods 之前一定要先确认底层网络的 IP 池够不够用。4.2 kubeconfig 与 kube-proxy 配置要点kubeconfig 是 Kubernetes 中几乎“无所不在”的配置文件。它不仅给 kubectl 用kubelet、kube-proxy、controller-manager、scheduler 这些组件也都通过 kubeconfig 来对接 apiserver。一个 kubeconfig 文件的核心结构是 clusters、users、contexts 三个数组加一个 current-contextapiVersion: v1 kind: Config clusters: - name: prod-cluster cluster: server: https://10.0.0.10:6443 certificate-authority-data: base64-ca users: - name: admin user: client-certificate-data: base64-cert client-key-data: base64-key contexts: - name: prod-admin context: cluster: prod-cluster user: admin理解这个结构后很多问题就清晰了切换集群无非是换 server 和证书报错 “server gave HTTP response to HTTPS client” 说明地址写成了 http 但客户端用了 https报证书过期就要看 users 里那块 client-certificate-data 是否还在有效期内。kube-proxy 的配置也是类似但多了一组模式相关参数比如apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs ipvs: masqueradeAll: true scheduler: rr clusterCIDR: 10.244.0.0/16 conntrack: maxPerCore: 32768集群里 Service 少、规模小的时候iptables 模式够用节点多、Service 上千建议先切 IPVS。但切换前要确保节点上有 ipvs 相关内核模块并检查 kube-proxy 的启动日志没有 fatal 报错否则会大面积丢规则。4.3 静态 Pod 清单与控制面组件启动参数控制面组件apiserver、controller-manager、scheduler以及共存模式的 etcd在自建集群里通常以静态 Pod 的方式运行。静态 Pod 的意思是不通过 apiserver 创建而是由 kubelet 直接监控一个指定目录staticPodPath通常是 /etc/kubernetes/manifests看到这个目录下的 Pod 清单文件就自动拉起删掉文件就自动停止。这个设计保证了即使 apiserver 完全不可用控制面组件也能被 kubelet 拉起来。以 apiserver 的静态 Pod 清单为例apiVersion: v1 kind: Pod metadata: name: kube-apiserver namespace: kube-system spec: hostNetwork: true containers: - name: kube-apiserver image: 镜像地址 command: - kube-apiserver - --etcd-servershttps://10.0.0.11:2379,https://10.0.0.12:2379 - --service-cluster-ip-range10.96.0.0/12 - --client-ca-file/etc/kubernetes/pki/ca.crt - --tls-cert-file/etc/kubernetes/pki/apiserver.crt - --tls-private-key-file/etc/kubernetes/pki/apiserver.key - --authorization-modeNode,RBAC volumeMounts: - mountPath: /etc/kubernetes/pki name: k8s-certs readOnly: true volumes: - hostPath: path: /etc/kubernetes/pki name: k8s-certs静态 Pod 清单改完不会自动生效需要 kubelet 感知到文件变化。实际操作中改完文件后要么等 kubelet 的扫描周期要么主动重启 kubelet或者干脆 mv 出去再 mv 回来触发感知。直接编辑运行中的静态 Pod 清单文件时YAML 写错了会导致组件反复 CrashLoopBackOff这时候最安全的做法是先把文件移走让 Pod 停掉修正后再放回来。kubelet 本身的启动参数走 systemd unit。一份典型配置包含 --kubeconfig 指向 kubelet 自己的 kubeconfig--config 指向上面说过的 KubeletConfiguration--container-runtime-endpoint 指定 CRI socket如 unix:///run/containerd/containerd.sock。改 kubelet 的 systemd 参数后要 systemctl daemon-reload 再 restart很多人漏了 daemon-reload 导致参数没生效还以为改了没用。5. 实战运维服务管理、日志与健康检查5.1 systemd 服务管理实操自建集群里Node 侧的 kubelet 和 kube-proxy 一般由 systemd 托管。日常最常用的命令我整理成一组systemctl status kubelet systemctl restart kubelet journalctl -u kubelet -f journalctl -u kubelet --since today -p err systemctl daemon-reload systemctl restart kube-proxy注意systemctl restart 在 kubelet 这种长期运行的组件上是“最后手段”不是“第一手段”。大多数情况下kubelet 出问题要么是配置写错、要么是证书失效、要么是 apiserver 连不上重启只能暂时掩盖很快会再次失败。正确顺序是先看日志定位根因再操作。控制面侧的静态 Pod 不归 systemd 管归 kubelet 管所以操作方式完全不同。改清单、重启组件都是通过调整 /etc/kubernetes/manifests 目录下的文件来完成。我在实操中经常会用 crictl 来查看控制面容器的状态crictl ps -a | grep kube-apiserver crictl logs container-id crictl inspect container-idcrictl 是 CRI 兼容的命令行工具比 docker 命令在 K8s 环境下更直接。节点上装好 crictl 并配置好 endpoint 后大部分容器运维操作都能在一个工具里完成我甚至会用它来做“伪 kubectl”——比如查看节点上所有 Pod 的容器状态而不依赖 apiserver 是否可用。5.2 关键日志分析与排错入口日志是排错的第一现场但“看日志”也要讲章法。我建议按这个优先级来先是 kubectl describe 看事件这是离业务最近、信息最友好的一层再是具体 Pod 的容器日志最后才是组件日志kubelet、kube-proxy、apiserver、etcd。组件日志里最常见的几类问题特征非常明显。apiserver 日志出现大量 “Failed to dial 2379” 或 “etcdserver: request timed out”十有八九是 etcd 慢或 etcd 集群脑裂kubelet 日志出现 “Unable to connect to the server: x509: certificate has expired or is not yet valid”就是证书问题kube-proxy 日志里刷 “failed to ensure that node ... has 0 endpoints”说明 Endpoint 同步异常Service 后端的 Pod 可能被误清。日志总量大时不要直接 tail 整个文件先用 grep 关键词过滤。比如journalctl -u kubelet --since 30 min ago | grep -i error\|fail\|refused这个方法能快速定位异常的“时域”再顺着时间点往前拉上下文。我个人的经验是90% 的集群故障在日志里都能找到直接证据真正需要重启解决的少之又少。5.3 证书、鉴权与安全加固经验证书问题是自建集群排错的高发区尤其是跑了一两年的集群。控制面的 PKI 文件一般放在 /etc/kubernetes/pki 下常见的有 ca.crt、apiserver.crt、etcd 相关证书、front-proxy-ca.crt 等。证书到期后组件之间握手失败现象千奇百怪kubectl 报 unable to connect、kubelet 一直 Unauthorized、apiserver 之间互相不信任。检查证书有效期是个基本操作openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A2 Validity如果启用了 kubeadm 的自动轮换Node 侧的 kubelet 客户端证书会自动续期但控制面静态 Pod 里的证书不会需要人工或借助外部工具处理。所以生产集群一定要把证书到期时间纳入监控提前一个月处理都不算早。安全加固方面最低底线是开启 RBAC 并遵循最小权限原则给业务账号只授权必要的 namespace 和资源操作。apiserver 的 --authorization-mode 必须包含 RBAC而且建议 Node 和 RBAC 同时启用。Service Account 的自动挂载 token 如果业务不需要在 Pod 上显式设置 automountServiceAccountToken: false。etcd 侧也要做客户端证书认证绝对不能裸跑在公网可达的端口上。6. 常见问题排查与避坑指南把我在实际运维里踩过、也看别人踩过的高频问题整理成一张速查表排查时可以直接对照。现象最可能的原因快速排查命令处理建议Node 显示 NotReadykubelet 与 apiserver 失联或 kubelet 崩溃journalctl -u kubelet -n 200先看日志确定是网络、证书还是配置问题Pod 一直 Pending资源不足、污点未容忍、调度器异常kubectl describe pod看 Events 里的调度提示90% 能直接定位Pod ContainerCreating 卡住镜像拉取失败、CNI 网络未就绪、PVC 未绑定crictl ps -a 加 kubectl describe pod分别查镜像仓库连通性、CNI 插件日志、PV/PVC 状态Service 访问不通后端 Endpoint 为空或 kube-proxy 规则异常kubectl get endpointskubectl logs kube-proxy先确认 Pod 是否 Ready再看 kube-proxy 模式与规则apiserver 响应变慢etcd 写延迟高、连接数暴增、请求洪峰查 etcd 指标fsync、leader优先优化 etcd 存储再考虑调 apiserver 并发参数组件报证书过期PKI 证书到期未做轮换openssl x509 检查证书有效期提前续期并更新所有引用证书的组件kubelet 启动失败cgroupDriver 不一致、配置语法错误journalctl -u kubelet 看首条报错修正配置后 daemon-reload 再启动HPA 不工作metrics-server 不可用或指标采集异常kubectl top node 或 kubectl get --raw /apis/metrics.k8s.io检查聚合层配置和 metrics-server 证书6.1 从一次典型故障看完整排查思路举例来说一个常见的组合故障某天业务反馈 Service 访问间歇性超时kubectl get nodes 看到其中一个 Node NotReady上面还跑着大量业务 Pod。这时正确的排查顺序是先看那个 NotReady 节点的 kubelet 日志确认是网络闪断还是 kubelet 本身被 OOM再确认节点恢复后流量的回切是否正常同时检查 Service 的 Endpoint 列表确认 NotReady 期间后端是否被摘除以及摘除/恢复的时机是否符合预期。我遇到过一个案例某节点内存长期紧张kubelet 被 OOM 杀掉节点进入 NotReady但 kube-proxy 还活着导致 Service 一直把流量转发到该节点而节点上容器其实已经大量失败。这类“半死不活”的节点最可怕比直接宕机更难发现。我的经验是监控里不光盯 Node 的 Ready 状态还要盯 kubelet 进程的存活、节点的内存/磁盘水位、以及 Service 后端 Endpoint 的数量变化任何异常波动都要及时处理。6.2 排错工具与命令速查最后给一张我自己常用的“工具清单”按使用频率排序kubectl describe看事件、看状态解决 80% 的业务层问题。crictl节点侧排查容器apiserver 挂了也能用。journalctl看 kubelet 和 kube-proxy 的系统日志。openssl检查证书处理一切 TLS 相关疑难杂症。etcdctl备份、恢复、检查 etcd 健康状态和数据。这五样工具配合起来几乎能覆盖自建集群的所有日常故障场景。工具不在多关键是熟悉每个工具“能看什么、不能看什么”排查时才能少走弯路。我自己在实际交付集群时最深的体会是Kubernetes 排错没有玄学绝大多数问题都能靠“组件职责 日志 配置检查”这三板斧定位。与其在出了问题的时候靠重启碰运气不如平时就把控制面、Node、配置文件和证书状态纳入常规巡检把这些基础做扎实比任何“一键脚本”都管用。如果你现在还没有一套自己的巡检清单强烈建议从 Node 状态、证书有效期、etcd 备份这三个点开始先把最要命的短板补上。