K8s节点失联排查手册:当kubelet突然找不到master节点时该怎么办?
Kubernetes节点失联深度排查:从“找不到Master”到集群恢复的实战指南
凌晨三点,告警平台的短信把手机屏幕点亮,一行刺眼的红色文字:“K8s节点失联,Pod调度失败”。你从床上弹起来,打开电脑,登录集群,kubectl get nodes 命令返回的结果里,那个本该承载着核心服务的节点状态变成了 NotReady,更糟糕的是,kubectl logs 命令直接报错:The connection to the server 192.168.2.129:6443 was refused。紧接着,查看节点上的 kubelet 日志,你看到了那个熟悉又令人头疼的错误:kubelet.go:2461] “Error getting node“ err=“node \“k8s-master\“ not found“。
这不是第一次了。在复杂的生产环境中,Kubernetes 节点与 Master 失联是运维人员最不愿遇到却又无法完全避免的故障之一。它不像某个 Pod 崩溃那样影响局部,而是直接切断了一个计算节点与集群大脑的连接,导致其上的所有工作负载陷入“孤岛”状态,无法被管理、无法被调度、也无法正常提供服务。对于依赖 Kubernetes 稳定性的企业来说,这种故障意味着服务中断的风险和潜在的业务损失。
面对这样的场景,慌乱地重启服务往往不是最佳选择。一个系统化的、基于故障树分析(FTA)的排查思路,才是快速定位问题、恢复集群健康的关键。本文将从一个资深 SRE 的视角出发,为你构建一套从表象到根源、从网络到配置的完整排查体系。我们不仅会解决眼前的“找不到 Master”问题,更会深入理解其背后的机制,让你在下一次告警响起时,能够胸有成竹。
1. 第一响应:建立诊断基线并快速验证网络层
当节点失联告警触发时,首要任务是保持冷静,并迅速建立一个清晰的诊断基线。盲目操作可能会掩盖问题线索,甚至导致故障扩散。
第一步,确认故障范围。 是单个节点失联,还是多个节点同时出现问题?使用一个健康的、能够连接 API Server 的节点(通常是另一个 Master 节点或运维跳板机)执行以下命令:
# 查看所有节点状态,确认故障节点
kubectl get nodes -o wide
# 查看故障节点上的 Pod 状态(从集群视角)
kubectl get pods -o wide --all-namespaces | grep <故障节点IP或主机名>
# 描述故障节点,获取更多事件信息
kubectl describe node <故障节点名>
如果 kubectl 命令本身报连接 API Server 失败,那说明问题可能出在控制平面(所有 Master 节点)或网络层面,需要优先排查 API Server 服务本身。如果只有特定节点失联,则聚焦于该节点与 Master 之间的通信链路。
紧接着,我们必须直击最可能的“元凶”:网络连通性。 Kubernetes 集群的神经中枢是 API Server(默认端口 6443),kubelet 需要持续地与它保持心跳(Node Lease)并汇报状态。网络层面的阻断是导致“找不到 Master”的最常见原因。
你需要登录到失联的节点上,执行一系列网络诊断命令:
# 1. 检查到 Master API Server 端口的连通性
# 假设你的 Master 节点 IP 是 192.168.2.129
ping 192.168.2.129
telnet 192.168.2.129 6443
# 或者使用更现代的 nc (netcat)
nc -zv 192.168.2.129 6443
# 2. 检查本地端口监听情况,确认 kubelet 是否在监听自己的端口(如10250)
sudo netstat -tlnp | grep kubelet
# 3. 检查本地防火墙规则(以 firewalld 为例)
sudo firewall-cmd --list-all
# 或者检查 iptables
sudo iptables -L -n | grep -E '(6443|10250)'
# 4. 检查路由表,确保到 Master 网络的路由正确
ip route get 192.168.2.129
# 5. 检查网络接口和 DNS 解析(如果 Master 使用主机名)
cat /etc/hosts
nslookup kubernetes.default.svc.cluster.local
注意:在云环境或使用了网络插件(如 Calico、Flannel)的集群中,还需要检查 CNI 插件是否正常。一个快速的检查方法是看
kube-system命名空间下网络相关的 Pod 是否运行正常,以及节点上的 CNI 配置文件(如/etc/cni/net.d/)是否存在且有效。
如果 telnet 6443 失败,而 ping 通,那么问题很可能出在防火墙、安全组或 API Server 服务本身。这时,你需要去 Master 节点检查 API Server 的 Pod 或服务状态,以及 Master 节点上的防火墙规则是否放行了 6443 端口来自工作节点的流量。
为了更清晰地对比网络排查要点,可以参考下表:
| 排查层面 | 检查命令/位置 | 正常表现 | 异常可能原因 |
|---|---|---|---|
| 节点间连通性 | ping <Master-IP>, nc -zv <Master-IP> 6443 | 能 ping 通,端口可连接 | 物理网络中断、交换机故障、云安全组未放行 |
| 本地防火墙 | firewall-cmd --list-all, iptables -L -n | 有允许 6443 端口的规则 | 防火墙规则丢失或错误,阻止了出站/入站连接 |
| K8s 服务发现 | nslookup kubernetes.default.svc.cluster.local | 解析出 ClusterIP | CoreDNS 故障,/etc/resolv.conf 配置错误 |
| CNI 网络插件 | kubectl get pod -n kube-system | grep -E '(calico|flannel|cilium)' | 所有 Pod 为 Running | 网络插件 Pod 崩溃,CNI 二进制文件缺失或配置错误 |
| 主机路由 | ip route get <Master-IP> | 显示明确且可达的路由 | 路由表混乱,多网卡配置冲突 |
完成这一轮快速网络检查,你可能已经解决了因安全组变更、防火墙误操作或临时网络抖动导致的问题。如果网络层一切正常,那么我们需要向更深处挖掘。
2. 深入服务层:剖析 kubelet 与 API Server 的运行状态
当网络通路确认无误后,注意力就该转移到服务本身。kubelet 是节点上的“节点代理”,它负责与 Master 通信,也是报错信息的直接来源。而 Master 端的 API Server 则是它唯一的对话对象。
首先,在问题节点上对 kubelet 进行一个全面的健康检查:
# 1. 检查 kubelet 服务状态
sudo systemctl status kubelet -l
# 重点查看 Active 状态是否是 `active (running)`,以及下面是否有明显的错误日志。
# 2. 如果状态异常,查看更详细的日志
sudo journalctl -xeu kubelet --since "1 hour ago"
# 使用 `-f` 参数可以实时跟踪日志输出。
# 3. 检查 kubelet 的关键配置文件
sudo cat /etc/kubernetes/kubelet.conf
# 关注 `server` 字段,是否正确指向了 API Server 的地址(可能是负载均衡器地址)。
sudo cat /var/lib/kubelet/config.yaml
# 检查 kubelet 的认证、证书等配置。
# 4. 检查 kubelet 进程是否存活,以及资源占用
ps aux | grep kubelet
top -p $(pgrep kubelet)
在 journalctl 输出的日志中,除了“node not found”,还需要关注以下几类关键信息:
- 证书相关错误:如
x509: certificate has expired or is not yet valid,failed to load TLS config。这直接指向认证问题。 - 连接拒绝:如
connection refused,dial tcp ... i/o timeout。这通常意味着对端 API Server 没有在监听端口,或者中间有网络策略阻断。 - 权限不足:如
... is forbidden: User \"system:node:...\" cannot ...。这表示该节点的身份(由证书标识)没有足够的 RBAC 权限。
其次,我们需要验证 Master 端 API Server 的健康状况。 如果可能,登录到一个健康的 Master 节点进行操作:
# 1. 检查 API Server 的静态 Pod 或服务状态(取决于安装方式)
# 如果是 kubeadm 安装,API Server 通常以静态 Pod 运行在 Master 节点上
sudo crictl pods | grep kube-apiserver
# 或者使用 docker(如果使用 docker 作为运行时)
sudo docker ps | grep kube-apiserver
# 2. 检查 API Server 的服务监听端口
sudo netstat -tlnp | grep 6443
# 3. 直接调用 API Server 的健康端点
curl -k https://localhost:6443/healthz
# 应该返回 `ok`。也可以从其他节点用 ClusterIP 测试:
curl -k https://<API-Server-ClusterIP>:6443/healthz
如果 API Server 本身不健康,那么所有节点都会出现问题,故障范围会更大。此时需要检查 Master 节点的系统资源(CPU、内存、磁盘)、etcd 集群状态等。
一个常见的、容易被忽略的故障点是:kubelet 与 API Server 之间的证书认证失败。Kubernetes 集群内部通信高度依赖 TLS 双向认证。kubelet 持有的客户端证书可能已经过期,或者 API Server 的服务器证书不被 kubelet 信任。
检查证书有效期的快速方法:
# 在问题节点上,检查 kubelet 客户端证书
sudo openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -noout -dates
# 输出中的 `notAfter` 就是过期时间。
# 检查 kubelet 服务账户令牌(如果使用)
sudo cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d '.' -f2 | base64 -d | jq .exp
# 需要安装 jq 工具。
# 在 Master 节点上,检查 API Server 的证书
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates
证书过期是导致节点突然失联的一个经典原因,尤其是在那些运行了很长时间而忘记设置证书自动更新的集群中。如果发现证书过期,需要使用 kubeadm certs renew 等工具进行更新,并重启相关组件。
3. 解密配置与认证:RBAC、Bootstrap 与证书陷阱
如果网络通畅、服务运行,但 kubelet 依然无法注册或报告“node not found”,那么问题很可能出在更深层的配置和认证授权环节。这里的水更深,也更能体现排查工作的专业性。
首先,审视 RBAC(基于角色的访问控制)。 kubelet 在 API Server 眼中是一个名为 system:node:<nodeName> 的用户。它需要一系列权限来更新自己的节点状态、创建 Lease 对象等。这些权限通常由 Node 授权模式和 system:node 相关的 ClusterRoleBinding 赋予。
你可以通过以下方式检查节点的 RBAC 权限是否被意外修改或删除:
# 从一个健康节点,检查 ClusterRoleBinding
kubectl get clusterrolebinding -o json | jq -r '.items[] | select(.subjects[]?.name=="system:nodes") | .metadata.name'
# 查看具体的 ClusterRole 权限
kubectl describe clusterrole system:node
# 关注是否有对 `nodes`, `leases.coordination.k8s.io` 资源的 get, update, patch 等动词权限。
我曾经遇到过一个案例,运维人员为了“安全收紧”,修改了全局的 ClusterRole,无意中移除了 system:nodes 组对 leases 资源的访问权限,导致所有节点在 Lease 续期时失败,日志中就会出现 cannot get resource "leases" in API group "coordination.k8s.io" 的 forbidden 错误。
其次,关注 kubelet 的启动和引导(Bootstrap)过程。 对于使用 kubeadm 加入的节点,或者启用了 TLS Bootstrapping 的集群,kubelet 最初会使用一个低权限的 bootstrap-kubeconfig 文件启动,然后向 API Server 申请证书签名请求(CSR),批准后才会获得正式的身份凭证。
这个流程中的任何一环出错,都会导致节点无法获得合法身份。排查点包括:
- Bootstrap Token 是否过期或失效:
kubeadm token list - CSR 是否被批准:
kubectl get csr。一个健康的、已加入节点的 CSR 状态应为Approved,Issued。 - kubelet 的
kubeconfig文件是否正确生成:比较/etc/kubernetes/kubelet.conf与/etc/kubernetes/bootstrap-kubelet.conf。前者应该包含有效的客户端证书。
这里有一个真实的配置陷阱:节点主机名或 IP 地址变更。Kubernetes 节点身份与它的主机名强绑定。如果你克隆了一台虚拟机作为新节点,或者修改了节点的主机名,但未清理旧的证书和配置,就会导致身份混淆。kubelet 试图以新主机名注册,但 API Server 发现已有同名节点,或者证书中的 Subject Alternative Name (SAN) 不匹配,从而拒绝请求。日志中可能会出现 node \"xxx\" cannot modify node \"yyy\" 这类令人困惑的错误。
处理方法是彻底清理旧节点信息并重新加入:
# 在 Master 上驱逐并删除旧节点(谨慎操作,会触发 Pod 迁移)
kubectl drain <old-node-name> --ignore-daemonsets --delete-local-data
kubectl delete node <old-node-name>
# 在问题节点上,清理 kubelet 工作目录和证书
sudo kubeadm reset -f
sudo rm -rf /etc/kubernetes/ /var/lib/kubelet/ /var/lib/etcd/(如果是 etcd 成员)
# 重新使用 kubeadm join 命令加入集群
4. 高级诊断与根因分析:日志、追踪与集群状态审计
当常规手段都未能定位问题时,就需要动用更高级的诊断工具和技术,进行根因分析(RCA)。这就像刑侦破案,需要从各个角落寻找蛛丝马迹。
深入挖掘日志。我们之前用了 journalctl 查看 kubelet 日志,但可能还不够。调整日志级别可以获取更详细的信息:
# 临时调整 kubelet 日志级别为更详细的 v=4 或 v=5
# 编辑 kubelet 的 systemd 配置文件,通常在 /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# 在 `ExecStart=` 行的最后添加 `--v=4`
sudo sed -i 's/$/ --v=4/' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 查看重启后的详细日志
sudo journalctl -xeu kubelet --since "now" | grep -E "(node.*not found|forbidden|error.*getting.*node)"
# 事后记得将日志级别调回,避免磁盘被日志塞满。
在 --v=4 或更高级别的日志中,你可以看到 kubelet 与 API Server 每一次通信的细节,包括发送的请求 URL、收到的响应状态码。这对于诊断权限问题、资源路径问题非常有帮助。
利用 Kubernetes 自身的调试工具。 kubectl 提供了一些强大的调试命令:
# 1. 检查集群事件,看是否有与节点相关的事件
kubectl get events --all-namespaces --sort-by='.lastTimestamp' | grep -i node
# 2. 检查节点控制器(Node Controller)和节点生命周期管理器的状态(需要访问 Master 组件日志)
# 节点控制器是 kube-controller-manager 的一部分
sudo journalctl -u kube-controller-manager | grep -i node
# 3. 使用 `kubectl describe node` 查看节点的完整状态和条件(Conditions)
kubectl describe node <node-name>
# 关注 `Conditions` 部分,如 `Ready`, `MemoryPressure`, `DiskPressure`, `PIDPressure`, `NetworkUnavailable` 等。
# 这些条件可以告诉你节点不健康的具体原因(如磁盘已满)。
进行集群状态审计。 有时候,问题不是出在失联的节点上,而是出在集群的全局状态上。例如:
- etcd 集群健康度:etcd 是 Kubernetes 的大脑数据库。如果 etcd 出现 leader 选举、网络分区或磁盘性能问题,API Server 的读写操作就会异常,间接导致节点状态更新失败。检查 etcd 集群状态:
# 在 etcd 容器或进程所在节点执行 ETCDCTL_API=3 etcdctl --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 endpoint health - API Server 的资源压力:检查 Master 节点的 CPU、内存、磁盘 I/O。API Server 过载会导致请求响应变慢甚至超时,kubelet 的心跳可能因此超时,导致节点被标记为
NotReady。 - 网络策略(NetworkPolicy)或服务网格(Service Mesh)的干扰:如果集群中部署了复杂的网络策略或 Istio 等服务网格,它们可能会在不知情的情况下拦截或修改 kubelet 与 API Server 之间的流量。检查相关的网络策略和 sidecar 注入配置。
最后,建立一个预防性的监控和告警体系,远比事后排查更重要。你应该监控以下指标,并在出现异常趋势时提前告警:
- 节点
Ready状态的变化 - kubelet 心跳间隔的异常(
node_heartbeat_interval_seconds) - API Server 的请求延迟和错误率
- 证书的过期时间(使用
kube-cert-manager或类似工具监控) - 系统组件的日志错误率(通过 Loki、Elasticsearch 等日志聚合工具)
回到我们开头那个凌晨三点的故障。通过上述系统化的排查,我们最终发现原因是:一个自动化安全扫描工具临时修改了节点的 iptables 规则,意外丢弃了通往 API Server 负载均衡器 IP 的 TCP 包。在恢复了 iptables 规则并重启 kubelet 后,节点在几分钟内重新加入了集群,状态恢复为 Ready。
处理 Kubernetes 节点失联问题,没有一成不变的银弹。它考验的是你对 Kubernetes 架构的深刻理解、对运维流程的熟练掌握,以及面对压力时清晰的排查思路。将这套故障树分析法内化为你的肌肉记忆,当下一次屏幕再次亮起红色告警时,你就能从容应对,快速让集群恢复绿色。记住,最好的故障处理,是让故障根本不要发生。因此,在集群平稳运行时,定期进行上述环节的“消防演练”和健康检查,同样至关重要。
更多推荐
所有评论(0)