最近在调试Kubernetes集群时,我遇到了一个经典问题:Node节点突然无法连接API服务器,报错显示"dial tcp 127.0.0.1:8080: connect: connection refused"。这就像你拿着门禁卡去公司,却发现刷卡机完全不响应一样让人抓狂。经过多次实战排查,我发现这个问题背后可能藏着至少五种常见原因。
首先需要理解这个报错的本质。当kubectl尝试连接API服务器时,它默认会通过127.0.0.1:8080这个本地地址进行通信。如果连接被拒绝,通常意味着API服务器没有在这个端口监听,或者网络策略阻止了连接。有意思的是,这个错误在新手搭建集群时特别常见,我见过不少工程师第一次部署K8s时都会卡在这个环节。
最容易忽视的往往是基础配置。KUBECONFIG环境变量就像是指向集群的GPS导航,如果设置错误,kubectl就会"迷路"。我遇到过这样的情况:明明已经复制了config文件到节点,却依然报错。后来发现是因为用户切换后环境变量没有继承。
验证方法很简单:
bash复制echo $KUBECONFIG
如果输出为空或者路径不正确,就需要重新设置:
bash复制export KUBECONFIG=/etc/kubernetes/admin.conf
更稳妥的做法是把这个配置写入用户的.bashrc或.zshrc文件:
bash复制echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
source ~/.bashrc
API服务器相当于K8s集群的大脑,如果它没有正常运行,整个集群就会"瘫痪"。有一次凌晨三点处理故障,发现原来是API服务器的容器意外退出了。检查方法很直接:
bash复制kubectl cluster-info
如果看到"Unable to connect to the server"的提示,就说明API服务器可能挂了。
更详细的检查可以查看API服务器pod状态:
bash复制kubectl get pods -n kube-system | grep apiserver
正常情况下应该看到类似"kube-apiserver-master"的pod状态为Running。
网络问题就像血管堵塞,会让集群的"血液"无法流通。我曾在某次迁移机房后遇到这个问题,后来发现是新环境的防火墙规则阻止了8080端口的通信。
测试网络连通性的黄金命令是:
bash复制telnet 127.0.0.1 8080
如果连接被拒绝,可以尝试检查本地端口监听情况:
bash复制netstat -tulnp | grep 8080
对于跨节点通信问题,还需要检查:
K8s的认证机制就像公司的门禁系统,配置错误会导致"有卡也进不去门"。我处理过一个案例:客户在config文件中误删了证书信息,导致所有节点都无法认证。
检查当前认证配置:
bash复制kubectl config view
重点关注:
有时候API服务器的服务端口可能被修改,就像公司突然换了大门位置。这种情况多发生在自定义安装或升级后。
检查API服务器实际监听端口:
bash复制ps -ef | grep kube-apiserver | grep --color=auto secure-port
默认安全端口是6443,如果看到不同值就需要调整config文件中的server地址。
当遇到连接问题时,我通常会先执行这三个命令:
bash复制# 检查环境变量
env | grep KUBE
# 检查API服务器状态
kubectl get componentstatuses
# 检查网络连通性
curl -k https://127.0.0.1:6443
日志就像系统的"病历本",能告诉我们很多信息。查看API服务器日志:
bash复制journalctl -u kube-apiserver -n 50 --no-pager
重点关注以下错误模式:
证书过期是另一个常见坑点。检查证书有效期:
bash复制openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates
如果证书已过期,就需要重新生成或续期。我曾经遇到过因为时区设置错误导致证书立即过期的情况。
对于刚搭建的集群,我建议按这个顺序检查:
一个完整的初始化后检查脚本:
bash复制#!/bin/bash
# 检查配置文件
ls -lah /etc/kubernetes/admin.conf
# 设置环境变量
export KUBECONFIG=/etc/kubernetes/admin.conf
# 测试连接
kubectl get nodes
这种情况更复杂,我的排查顺序是:
资源检查命令:
bash复制# 内存和CPU
top -n 1 | grep kube-apiserver
# 磁盘空间
df -h /var/lib/etcd
新节点加入时出现连接问题,通常需要:
验证token有效性的方法:
bash复制kubeadm token list
管理多个集群时,我推荐使用kubecm工具合并kubeconfig:
bash复制# 安装kubecm
curl -Lo kubecm.tar.gz https://github.com/sunny0826/kubecm/releases/download/v0.15.2/kubecm_0.15.2_Linux_x86_64.tar.gz
tar -zxvf kubecm.tar.gz
sudo mv kubecm /usr/local/bin/
# 合并config
kubecm merge -f ~/.kube/config
对于不稳定的网络环境,可以在kubectl命令中添加重试参数:
bash复制kubectl get pods --request-timeout=5s --retries=3
预防胜于治疗,我习惯配置这些监控项:
使用Prometheus的示例告警规则:
yaml复制groups:
- name: Kubernetes API Server
rules:
- alert: API Server Down
expr: up{job="apiserver"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Kubernetes API server is down"
某次部署后,API服务器只绑定了127.0.0.1,导致其他节点无法连接。解决方案是修改API服务器启动参数:
bash复制--bind-address=0.0.0.0
客户在证书中漏掉了节点IP,导致TLS握手失败。修复方法是重新生成证书并包含所有可能的IP和域名:
bash复制kubeadm init phase certs apiserver --apiserver-cert-extra-sans=node1.example.com,10.0.0.1
etcd数据损坏会导致API服务器无法启动。这种情况下需要:
etcd数据恢复基本步骤:
bash复制# 备份
ETCDCTL_API=3 etcdctl snapshot save snapshot.db
# 恢复
ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \
--initial-cluster-token=etcd-cluster-1 \
--initial-advertise-peer-urls=https://10.0.0.1:2380
根据集群规模调整这些参数可以显著提升稳定性:
yaml复制apiServer:
extraArgs:
http2-max-streams-per-connection: "1000"
max-mutating-requests-inflight: "600"
max-requests-inflight: "1200"
减少API服务器负载的一个技巧是启用客户端缓存:
bash复制kubectl get pods --cache --cache-timeout=60s
调整kubectl的默认连接池设置:
bash复制# 在~/.kube/config中添加
clusters:
- cluster:
tcp-keepalive: true
tcp-keepalive-interval: 30s
经过这些年的实践,我发现K8s节点连接问题虽然表象相似,但背后的原因可能千差万别。关键是要建立系统化的排查思路,从简单到复杂逐步验证。每次解决这类问题后,我都会把排查过程记录下来,形成自己的"故障模式库",这对快速定位问题特别有帮助。