[kubernetes]Calico运行异常:dial tcp 10.96.0.1:443: connect: connection refused

安装Calico后,pod未能进入Ready状态,报错:dial tcp 10.96.0.1:443: connect: connection refused。错误根源不在于iptables,而是由于10.96.0.1是kubernetes API的ClusterIP。集群内pod通过kube-proxy访问此服务。问题可能是kube-proxy未运行或异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

安装calico网络插件之后,发现相关pod一直不能进入Ready状态,查看log,出现如下问题:

Hit error connecting to datastore - retry error=Get “https://10.96.0.1:443/api/v1/nodes/foo”: dial tcp 10.96.0.1:443: connect: connection refused

网上查资料都说是什么iptables配置的问题,各种尝试,发现完全不对。于是打算从根源了解这个东西。

那么这个10.96.0.1到底是什么呢?原来

在 kubernetes,可以从集群外部和内部两种方式访问 kubernetes API,在集群外直接访问 apiserver 提供的 API,在集群内即 pod 中可以通过访问 service 为 kubernetes 的 ClusterIP。kubernetes 集群在初始化完成后就会创建一个 kubernetes service,该 service 是 kube-apiserver 创建并进行维护的,如下所示:

[root@master1 dingpwen]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2d20h

内置的 kubernetes service 无法删除,其 ClusterIP 为通过 --service-cluster-ip-range 参数指定的 ip 段中的首个 ip,kubernetes endpoints 中的 ip 以及 port 可以通过 --advertise-address 和 --secure-port 启动参数来指定。

那么我们Node上的pod又如何才能访问到这个服务呢?毕竟相对于master机器,Node机器通过ip访问相当于“外网”。

其实我们查看kube-proxy的代码就会发现

I0427 01:46:24.595581       1 config.go:233]
[reset] Unmounting mounted directories in "/var/lib/kubelet" W0321 14:19:36.524481 91940 cleanupnode.go:99] [reset] Failed to remove containers: [failed to stop running pod cdf897d2b8231f7d3fffa49017090a655b94ddb22cbc24d06f32d519fbaa2c5f: output: E0321 14:19:19.953922 92079 remote_runtime.go:205] "StopPodSandbox from runtime service failed" err="rpc error: code = Unknown desc = failed to destroy network for sandbox \"cdf897d2b8231f7d3fffa49017090a655b94ddb22cbc24d06f32d519fbaa2c5f\": plugin type=\"calico\" failed (delete): error getting ClusterInformation: Get \"https://10.96.0.1:443/apis/crd.projectcalico.org/v1/clusterinformations/default\": dial tcp 10.96.0.1:443: connect: connection refused" podSandboxID="cdf897d2b8231f7d3fffa49017090a655b94ddb22cbc24d06f32d519fbaa2c5f" time="2025-03-21T14:19:19+08:00" level=fatal msg="stopping the pod sandbox \"cdf897d2b8231f7d3fffa49017090a655b94ddb22cbc24d06f32d519fbaa2c5f\": rpc error: code = Unknown desc = failed to destroy network for sandbox \"cdf897d2b8231f7d3fffa49017090a655b94ddb22cbc24d06f32d519fbaa2c5f\": plugin type=\"calico\" failed (delete): error getting ClusterInformation: Get \"https://10.96.0.1:443/apis/crd.projectcalico.org/v1/clusterinformations/default\": dial tcp 10.96.0.1:443: connect: connection refused" : exit status 1, failed to stop running pod e4fee45416ccc066380fe4d0f2f28ca861bf836967d88f2074ce62d6d77ec9ed: output: E0321 14:19:20.255860 92242 remote_runtime.go:205] "StopPodSandbox from runtime service failed" err="rpc error: code = Unknown desc = failed to destroy network for sandbox \"e4fee45416ccc066380fe4d0f2f28ca861bf836967d88f2074ce62d6d77ec9ed\": plugin type=\"calico\" failed (delete): error getting ClusterInformation: Get \"https://10.96.0.1:443/apis/crd.projectcalico.org/v1/clusterinformations/default\": dial tcp 10.96.0.1:443: connect: connection refused" podSandboxID="e4fee45416ccc066380fe4d0f2f28ca861bf836967d88f2074ce62d6d77ec9ed" time="2025-03-21T14:19:20+08:00" level=fatal msg="stopping the pod sandbox \"e4fee45416ccc06638
03-22
<think>我们正在解决Kubernetes中provisioner(例如nfs-client-provisioner)无法连接API Server的问题,错误信息为: "Error getting server version: Get https://10.96.0.1:443/version?timeout=32s: dial tcp 10.96.0.1:443: i/o timeout" 根据引用[1][2][3][4]的描述,该问题表现为provisioner无法访问Kubernetes API Server(默认服务地址为10.96.0.1:443)。常见原因包括: 1. 网络插件(如Calico、Flannel)未正常运行,导致Pod无法访问ClusterIP。 2. 节点防火墙或路由规则阻止了Pod到API Server的通信。 3. 虚拟机挂起后重启导致网络配置异常(引用[4])。 4. 节点IP地址变更导致kube-proxy或网络插件配置失效。 引用[5]提供了一个相关案例:通过修改docker的cgroup驱动并重置kubeadm解决类似问题,但该案例针对的是kubelet连接问题,与当前问题场景不同,仅供参考。 以下是系统化的排查步骤: ### 步骤1:检查Kubernetes核心组件状态 ```bash kubectl get pods -n kube-system # 检查网络插件、kube-proxy等组件是否运行正常 ``` ### 步骤2:验证API Server的可访问性 在出现问题的Provisioner Pod所在节点上执行: ```bash # 进入Provisioner Pod所在节点 kubectl get pods -o wide # 查看Provisioner Pod运行在哪个节点 # 登录该节点,尝试从节点直接访问API Server curl -k https://10.96.0.1:443/version # 预期返回:{"kind":"Status","apiVersion":"v1","status":"Failure","message":"forbidden: User \"system:anonymous\" cannot get path \"/version\"","reason":"Forbidden","details":{},"code":403} # 注意:403状态码表示网络可达但未授权,这证明网络连接正常。如果出现超时(Timeout)则说明网络不通。 # 如果节点无法访问API Server,检查节点的网络配置: ip route show # 查看路由表 iptables -L -n -t nat # 检查NAT规则 ``` ### 步骤3:检查网络插件 如果节点无法访问API Server,重点检查网络插件: ```bash # 查看网络插件Pod日志 kubectl logs -n kube-system <network-plugin-pod-name> ``` ### 步骤4:检查kube-proxy kube-proxy负责将ClusterIP(如10.96.0.1)路由到API Server的实际端点: ```bash # 检查kube-proxy日志 kubectl logs -n kube-system kube-proxy-xxxxx # 确认kube-proxy是否正确配置 kubectl get cm -n kube-system kube-proxy -o yaml # 查看配置 ``` ### 步骤5:检查Provisioner Pod的网络连通性 在Provisioner Pod内部执行诊断: ```bash kubectl exec -it <provisioner-pod-name> -- sh # 在Pod内执行: curl -v https://10.96.0.1:443/version # 若超时,则检查Pod的DNS和网络: nslookup kubernetes.default # 应解析为10.96.0.1 ``` ### 步骤6:排查虚拟机挂起后的网络问题(引用[4]) 虚拟机挂起后重启可能导致网络接口异常或路由丢失: ```bash # 重启网络相关服务(根据操作系统) systemctl restart network # CentOS/RHEL systemctl restart networking # Ubuntu # 重启容器运行时和kubelet systemctl restart docker systemctl restart kubelet ``` ### 步骤7:重置kube-proxy(可选) 如果kube-proxy配置损坏,可尝试重置: ```bash kubectl delete pod -n kube-system -l k8s-app=kube-proxy ``` ### 步骤8:完全重置集群(终极方案) 如果以上步骤无效,考虑重置集群(谨慎操作): ```bash kubeadm reset -f systemctl stop kubelet systemctl stop docker rm -rf /var/lib/cni/ rm -rf /var/lib/kubelet/* rm -rf /etc/cni/ ifconfig cni0 down ifconfig flannel.1 down ifconfig docker0 down ip link delete cni0 ip link delete flannel.1 systemctl start docker systemctl start kubelet kubeadm init ... # 重新初始化 ``` ### 预防措施 1. **避免虚拟机挂起**:生产环境推荐使用物理机或可靠云主机。 2. **网络插件选择**:使用经过充分测试的网络插件(如Calico、Flannel),并定期更新。 3. **健康检查**:为关键组件(如provisioner)添加就绪探针,确保网络连通后才提供服务。 §§相关问题§§ 1. Kubernetes中如何诊断Pod网络问题? 2. 如何配置Kubernetes网络插件以实现高可用? 3. 虚拟机挂起后Kubernetes节点状态异常的恢复方法有哪些?</think>### Kubernetes Provisioner "Error getting server version: i/o timeout" 问题分析与解决 该错误表明 provisioner(如 NFS-Client Provisioner)无法连接到 Kubernetes API Server,通常发生在存储插件启动时。以下是根本原因和系统化解决方案: --- #### 问题根源分析 1. **网络连通性问题**(最常见) - Pod 无法访问 API Server 的 ClusterIP(默认 `10.96.0.1:443`) - 错误表现:`dial tcp 10.96.0.1:443: i/o timeout` 或 `no route to host`[^1][^2][^3][^4] 2. **核心组件异常** - kube-proxy 服务未运行或配置错误 - 网络插件(Calico/Flannel)故障 - 节点路由表损坏(虚拟机挂起后常见) 3. **证书或认证问题** - ServiceAccount 权限不足 - kubeconfig 配置错误 --- #### 解决方案(分步操作) ##### 步骤1:验证基础网络连通性 在 **Provisioner Pod 所在节点** 执行: ```bash # 检查能否解析API Server nslookup kubernetes.default.svc.cluster.local # 测试API Server端口连通性 telnet 10.96.0.1 443 # 或使用 nc -zv 10.96.0.1 443 ``` - 🔴 若失败:检查节点防火墙规则,确保开放 443/TCP 端口 - 🔴 若 `no route to host`:检查节点路由表 `ip route show` ##### 步骤2:检查核心组件状态 ```bash kubectl get pods -n kube-system | grep -E 'kube-proxy|calico|flannel' kubectl logs -n kube-system <kube-proxy-pod-name> ``` - 常见修复操作: ```bash # 重启kube-proxy kubectl delete pod -n kube-system -l k8s-app=kube-proxy # 重启网络插件(以Calico为例) kubectl rollout restart daemonset calico-node -n kube-system ``` ##### 步骤3:诊断DNS解析 在 **Provisioner Pod 内部** 执行诊断: ```bash kubectl exec -it <provisioner-pod-name> -- sh # 在Pod内执行: nslookup kubernetes.default.svc.cluster.local curl -vk https://kubernetes.default.svc.cluster.local:443/version ``` - 🔴 若DNS解析失败:检查CoreDNS状态 `kubectl get pods -n kube-system -l k8s-app=kube-dns` ##### 步骤4:检查RBAC权限(关键!) 确保Provisioner的ServiceAccount有足够权限: ```yaml # 示例RBAC配置(nfs-client-provisioner) apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: nfs-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] # 必须包含对version资源的访问权限! - apiGroups: [""] resources: ["version"] verbs: ["get"] ``` ##### 步骤5:虚拟机挂起后的特殊处理[^4] 虚拟机恢复后执行: ```bash # 重启容器运行时和kubelet sudo systemctl restart docker && sudo systemctl restart containerd sudo systemctl restart kubelet # 重置网络接口 sudo ip link set cni0 down && sudo brctl delbr cni0 sudo systemctl restart network ``` ##### 步骤6:终极重建方案 当以上无效时,完全重置集群组件: ```bash # 1. 重置kubeadm(所有节点执行) sudo kubeadm reset -f # 2. 清理网络残留 sudo ipvsadm --clear sudo rm -rf /etc/cni/net.d/* # 3. 重启节点 sudo reboot # 4. 重新初始化集群 sudo kubeadm init --apiserver-advertise-address=<node-ip> ``` --- #### 预防措施 1. **节点维护规范**: ```mermaid graph LR A[关机前] --> B[清空节点 kubectl drain] B --> C[关闭节点] C --> D[恢复后执行 kubectl uncordon] ``` 2. **配置健康检查**: ```yaml # 在Provisioner部署中添加就绪探针 readinessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 10 periodSeconds: 5 ``` 3. **网络插件优化**: - 使用Calico的BGP模式替代Flannel - 启用kube-proxy的IPVS模式:`kubectl edit cm -n kube-system kube-proxy` → 设置 `mode: "ipvs"` > **关键提示**:生产环境建议使用 `kubeadm upgrade` 而非直接关机维护,避免网络配置丢失[^4]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值