4. 证书轮换失败典型场景1:kubelet证书过期导致Node NotReady,调度器无法调度Pod到该节点
4.1 场景概述
在Kubernetes集群中,kubelet使用由集群CA签发的TLS证书与kube-apiserver进行双向认证。当kubelet证书过期且自动轮换机制失效时,kubelet将无法向控制平面发送心跳(NodeLease),导致节点状态在node-monitor-grace-period(默认40秒)后变为NotReady。调度器随后将该节点标记为不可调度,已运行的Pod被驱逐,新Pod无法调度至此节点。
⚠️ 关键影响: 证书过期导致的NotReady与网络分区不同——kubelet进程仍在运行,但所有与APIServer的通信均被TLS拒绝,节点上的Pod状态无法同步,导致调度器做出错误决策。
4.2 故障链路与根因分析
下图展示了从证书过期到调度异常的完整链路:
4.3 关键时间参数与影响
| 参数 | 默认值 | 作用 | 证书过期后的影响 |
|---|---|---|---|
--node-monitor-grace-period |
40s | 节点控制器等待心跳的最大时间 | 超过40秒未收到心跳,节点标记为 NotReady |
--node-status-update-frequency |
10s | kubelet上报节点状态的频率 | 证书过期后,状态更新立即失败 |
--pod-eviction-timeout |
5m | 节点NotReady后驱逐Pod的等待时间 | 5分钟后,节点上的Pod被标记为Terminating |
tolerationSeconds |
300s | Pod容忍节点不可达的时间 | 超过容忍时间后,Pod被驱逐 |
4.4 排查步骤与命令
📋 排查流程: 按照以下步骤快速定位证书过期导致的NotReady问题。
- 检查节点状态:
kubectl get nodes # 输出示例: # NAME STATUS ROLES AGE VERSION # node-1 NotReady <none> 30d v1.28.5 - 查看节点详情,确认Taint:
kubectl describe node node-1 | grep -A5 Taints # 输出示例: # Taints: node.kubernetes.io/unreachable:NoExecute # node.kubernetes.io/unreachable:NoSchedule - 检查kubelet日志,定位证书错误:
# SSH登录到节点后执行 journalctl -u kubelet -n 100 --no-pager | grep -i "certificate\|tls\|x509" # 典型错误: # "x509: certificate has expired or is not yet valid" # "failed to get recent kubelet config: failed to get kubelet config from api server" # "TLS handshake error from x.x.x.x: remote error: tls: bad certificate" - 检查证书过期时间:
# 查看kubelet当前使用的证书 openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -text -noout | grep -A2 "Validity" # 输出示例: # Validity # Not Before: Jan 10 12:00:00 2024 GMT # Not After : Jan 10 12:00:00 2025 GMT ← 已过期 - 验证证书轮换配置:
# 检查kubelet配置中证书轮换是否启用 kubectl get nodes node-1 -o yaml | grep -i "rotate" # 或SSH到节点检查kubelet配置文件 cat /var/lib/kubelet/config.yaml | grep -i "rotate" # 期望输出: # rotateCertificates: true # rotateServerCertificates: true
4.5 证书轮换机制对比
| 轮换类型 | 触发条件 | 证书类型 | 常见失败原因 |
|---|---|---|---|
| 客户端证书轮换 | kubelet启动时检查证书剩余时间 < 80% 有效期 | kubelet-client-current.pem |
CSR审批被拒绝、CA证书不匹配、kubelet无权创建CSR |
| 服务端证书轮换 | kubelet启动时检查证书剩余时间 < 80% 有效期 | kubelet-server-current.pem |
kubelet配置中 rotateServerCertificates: false |
| 手动轮换 | 管理员手动删除旧证书文件并重启kubelet | 所有kubelet证书 | 证书目录权限错误、kubelet无法读取新证书 |
4.6 快速恢复方案
💡 应急恢复步骤: 当确认是kubelet证书过期导致NotReady时,按以下顺序执行恢复。
- 方案一:手动触发证书轮换(推荐)
# 1. 删除过期证书文件 rm -f /var/lib/kubelet/pki/kubelet-client-current.pem rm -f /var/lib/kubelet/pki/kubelet-server-current.pem # 2. 重启kubelet服务 systemctl restart kubelet # 3. 验证新证书是否生成 ls -la /var/lib/kubelet/pki/kubelet-client-current.pem # 4. 确认节点状态恢复 kubectl get nodes node-1 # 等待约40秒后状态应变为 Ready - 方案二:手动签发证书(当自动轮换完全失效时)
# 1. 生成新的CSR openssl req -new -key /var/lib/kubelet/pki/kubelet-client.key \ -out /tmp/kubelet-client.csr \ -subj "/CN=system:node:node-1/O=system:nodes" # 2. 使用集群CA签发证书 openssl x509 -req -in /tmp/kubelet-client.csr \ -CA /etc/kubernetes/pki/ca.crt \ -CAkey /etc/kubernetes/pki/ca.key \ -CAcreateserial -out /var/lib/kubelet/pki/kubelet-client-current.pem \ -days 365 # 3. 重启kubelet systemctl restart kubelet - 方案三:临时容忍Taint(仅用于紧急调度)
# 为特定Pod添加容忍,使其可以调度到NotReady节点 kubectl patch pod <pod-name> -p '{"spec":{"tolerations":[{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute"}]}}'
4.7 预防措施与监控建议
⚠️ 长期预防: 证书轮换失败是集群中最容易被忽视的故障之一,建议在集群部署阶段就完成以下配置。
- 启用自动轮换: 在kubelet配置中设置
rotateCertificates: true和rotateServerCertificates: true - 监控证书过期时间: 使用Prometheus + Grafana监控kubelet证书剩余天数,建议在证书到期前30天告警
- 配置CSR自动审批: 部署
kubelet-rubber-stamp或配置RBAC允许kubelet自动审批自己的CSR - 定期巡检: 每月执行证书检查脚本,输出所有节点的证书过期时间
- 证书有效期规划: 建议将kubelet证书有效期设置为1年,与集群CA证书有效期对齐
4.8 典型错误日志速查表
| 错误日志 | 含义 | 解决方案 |
|---|---|---|
x509: certificate has expired or is not yet valid |
证书已过期或尚未生效 | 删除过期证书,重启kubelet触发轮换 |
failed to get recent kubelet config |
kubelet无法从APIServer获取配置 | 检查kubelet证书和APIServer连通性 |
csr not found or not approved |
CSR未被审批 | 检查CSR状态,手动审批或配置自动审批 |
certificate signed by unknown authority |
证书签发者不被信任 | 检查CA证书是否匹配,重新签发证书 |
TLS handshake error: bad certificate |
TLS握手时证书验证失败 | 检查证书链是否完整,证书格式是否正确 |