1. 初识K8s集群初始化超时问题
最近在部署Kubernetes 1.19集群时,遇到了一个让人头疼的问题:控制平面初始化时卡在等待阶段,报错显示[kubelet-check] Initial timeout of 40s passed。这个错误看似简单,但背后却隐藏着不少玄机。作为一个踩过这个坑的老司机,我想分享一下我的排查过程和解决方案。
刚开始看到这个错误时,我以为是kubelet服务没启动好,于是按照提示检查了systemctl status kubelet和journalctl日志,但都没发现明显异常。接着我又怀疑是cgroup配置问题,检查了相关参数也没发现问题。这时候我才意识到,问题可能出在更底层的地方。
2. 深入分析kubelet健康检查机制
2.1 kubelet健康检查的工作原理
kubelet是Kubernetes集群中的关键组件,负责维护节点上容器的正常运行。在集群初始化过程中,kubeadm会通过健康检查来确认kubelet是否就绪。这个检查有两个关键点:
- 40秒超时机制:kubeadm默认会给kubelet 40秒的启动时间
- 就绪条件:kubelet需要能够与API Server建立有效通信
在实际操作中,我发现即使kubelet服务已经启动,如果它无法正确连接到API Server,也会触发这个超时错误。这就引出了一个问题:为什么kubelet连不上API Server?
2.2 证书与网络连接的关系
仔细查看初始化日志,我注意到一个关键信息:证书生成时使用的IP地址。在错误的配置中,证书是为外部IP(1.2.3.4)生成的,而kubelet实际上是在尝试连接本地网络接口。这就造成了TLS握手失败,进而导致健康检查超时。
[certs] apiserver serving cert is signed for DNS names [k8s-master kubernetes...] and IPs [10.96.0.1 1.2.3.4]这个细节让我恍然大悟:证书中必须包含kubelet实际连接使用的IP地址,否则TLS验证就会失败。
3. advertiseAddress配置的陷阱与正确姿势
3.1 常见错误配置分析
很多人在配置advertiseAddress时会犯两个典型错误:
- 使用外部IP或域名:比如配置成公网IP或者域名
- 使用0.0.0.0:以为这样可以匹配所有接口
这两种配置都会导致证书生成不正确。特别是使用域名时,会遇到更直接的报错:
couldn't use "k8s.cnlogs.com" as "apiserver-advertise-address", must be ipv4 or ipv6 address3.2 正确的配置方法
正确的做法是使用master节点的实际内部IP地址。这个IP需要满足:
- 是节点上真实存在的网络接口IP
- 集群内其他节点能够访问到这个IP
- 与kubelet连接的地址一致
在我的环境中,将配置改为:
localAPIEndpoint: advertiseAddress: 10.0.128.0 bindPort: 6443这样就确保了证书生成、kubelet连接和实际网络接口三者一致。
4. 完整的排查与解决流程
4.1 分步解决方案
根据我的实战经验,解决这个问题需要以下步骤:
- 确认节点IP:使用
ip addr命令查看节点的实际IP地址 - 修改配置文件:确保init-config.yaml中的advertiseAddress使用正确的IP
- 重置环境:执行
kubeadm reset清理之前的错误配置 - 重新初始化:使用修正后的配置文件运行
kubeadm init
4.2 配置文件完整示例
以下是我最终使用的有效配置文件:
apiVersion: kubeadm.k8s.io/v1beta2 bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authentication kind: InitConfiguration localAPIEndpoint: advertiseAddress: 10.0.128.0 bindPort: 6443 nodeRegistration: criSocket: /var/run/dockershim.sock name: k8s-master taints: - effect: NoSchedule key: node-role.kubernetes.io/master --- apiServer: timeoutForControlPlane: 4m0s apiVersion: kubeadm.k8s.io/v1beta2 certificatesDir: /etc/kubernetes/pki clusterName: kubernetes controllerManager: {} dns: type: CoreDNS etcd: local: dataDir: /var/lib/etcd imageRepository: registry.aliyuncs.com/google_containers kind: ClusterConfiguration kubernetesVersion: v1.19.0 networking: dnsDomain: cluster.local podsubnet: 192.168.0.0/16 serviceSubnet: 10.96.0.0/16 scheduler: {}4.3 验证成功的标志
当配置正确后,初始化过程会显示以下关键信息:
[apiclient] All control plane components are healthy after 6.002090 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace这表明所有控制平面组件都已正常启动,集群初始化成功。
5. 深度技术原理剖析
5.1 证书生成机制
kubeadm在初始化时会自动生成一系列证书,这些证书中包含了API Server的可访问地址。关键点在于:
- Subject Alternative Names(SANs):证书中会包含API Server的所有有效访问地址
- IP与DNS名称:包括service网段IP、节点IP、DNS名称等
- 严格匹配:客户端连接时使用的地址必须与证书中的某个条目完全匹配
如果advertiseAddress配置错误,生成的证书就不包含kubelet实际使用的连接地址,导致TLS验证失败。
5.2 控制平面启动顺序
理解控制平面组件的启动顺序也很重要:
- etcd最先启动,为API Server提供存储后端
- API Server启动后,其他组件才能连接
- kubelet需要能够访问API Server来报告状态
这个依赖关系决定了如果API Server因为证书问题无法正常提供服务,整个初始化过程就会卡住。
6. 常见问题扩展与预防措施
6.1 多网卡环境下的特殊处理
在生产环境中,节点可能有多个网络接口。这时需要特别注意:
- 选择正确的网络接口IP作为advertiseAddress
- 确保所有节点间的网络连通性
- 如果有网络策略限制,需要开放必要的端口
6.2 高可用集群的配置差异
对于高可用集群,advertiseAddress通常要配置为负载均衡器的VIP。这种情况下:
- 证书中需要包含VIP和所有master节点的IP
- 需要额外配置负载均衡器
- kubelet配置也需要相应调整
6.3 预防性检查清单
为了避免类似问题,我总结了一个检查清单:
- 使用
ip addr确认网络接口配置 - 测试节点间网络连通性
- 检查防火墙规则,确保6443等端口开放
- 验证DNS解析(如果使用主机名)
- 提前拉取所需镜像,避免网络问题
7. 其他可能引起超时的原因
虽然advertiseAddress配置错误是常见原因,但还有其他可能性:
- 资源不足:节点内存或CPU不足导致组件启动缓慢
- 镜像拉取失败:网络问题导致关键镜像无法下载
- 存储问题:etcd数据目录权限不正确
- 版本不兼容:组件版本不匹配
对于这些情况,查看各组件的日志是定位问题的关键:
docker ps -a | grep kube docker logs <container_id>8. 实战经验与技巧分享
在多次部署K8s集群后,我总结了一些实用技巧:
- 预检脚本:使用kubeadm的
kubeadm config images pull提前拉取镜像 - 日志级别:初始化时添加
--v=5参数获取更详细日志 - 快速重置:
kubeadm reset -f可以强制重置环境 - 配置验证:使用
kubeadm config print init-defaults查看默认配置
对于复杂的生产环境,建议先在测试环境验证配置,然后再应用到生产环境。同时,保持所有节点的系统版本、依赖软件版本一致也很重要。