一、故障现场还原与初步感知

上周帮一个做边缘计算的客户排查问题,客户突然反馈说,部署在边缘机房的几个节点,没法访问云上的API Server了,而且之前刚做过证书轮换,按理说不该出这种问题,我先让客户在边缘节点上敲个简单的命令看看情况。

# 边缘节点上执行查看节点的命令,模拟实际报错输出
kubectl get nodes
# 报错信息:
# error: Get "https://192.168.1.100:6443/api/v1/nodes?limit=500": dial tcp 192.168.1.100:6443: i/o timeout

客户说证书明明刚换过,怎么还连不上,这时候第一反应不是证书本身,而是中间的云边通道——Yurt-Tunnel,因为边缘节点本来没有直接暴露的公网IP,所有访问API Server的请求都是通过这个通道传过去的,通道一断,就算证书没问题也白搭。

二、从tunnel-server到云上apiserver的全链路排查步骤

排查这种跨节点的网络问题,核心思路就是“从近到远,逐段验证”,就像找家里的WiFi断了,先看自己的手机,再看路由器,再看宽带进线一样。

2.1 第一步:确认tunnel-server本身的运行状态

先看通道的“大脑”——tunnel-server有没有正常跑起来,客户的集群是用K8s部署的,所以先查对应的Pod。

# 在云侧的tunnel-server所在节点,先查k8s里的相关Pod
kubectl get pods -n kube-system | grep yurt-tunnel
# 正常的话,应该有两个Pod(如果是高可用的话,最少1个),状态是Running
# 如果状态是CrashLoopBackOff,说明这个Pod已经出问题了,先看日志
kubectl logs -n kube-system yurt-tunnel-server-7f8d9c6b5-lz2xq
# 日志里如果有类似“can't connect to apiserver”的报错,那说明tunnel-server连不上API Server,这就是根因方向之一

2.2 第二步:验证边缘节点到tunnel-server的端口是否可达

边缘节点要把请求发给tunnel-server,所以得确认两个节点之间的端口能不能正常通信,Yurt-Tunnel默认用10250端口(也可能自定义),用nc命令测一下。

# 注意这个命令是在边缘节点上执行,换成本地的tunnel-server的IP和端口
nc -zv 10.10.20.30 10250
# 正常输出应该是:Connection to 10.10.20.30 10250 port [tcp/*] succeeded!
# 如果输出是Connection timed out或者Connection refused,说明要么端口没开,要么中间有防火墙挡了,要么tunnel-server没监听这个端口

2.3 第三步:确认tunnel-server到云上API Server的端口通不通

刚才是边缘到tunnel,现在看tunnel-server能不能连上真正的API Server,API Server默认端口是6443,在tunnel-server节点上测这个端口。

# 在tunnel-server节点上执行,用API Server的地址和端口
nc -zv kubernetes.default.svc 6443
# 如果也返回timeout,那说明tunnel-server这边连不上API Server,问题在云侧的API Server和通道之间
# 如果能连通,那问题可能出在通道的转发规则上,比如端口映射错了

2.4 第四步:检查tunnel的配置是否正确

如果前面的端口都通,但还是连不上,大概率是tunnel的配置文件里的信息错了,比如API Server的地址写错了,或者端口不匹配,查一下配置文件。

# 云侧ConfigMap里的tunnel配置,核心部分,带注释
apiVersion: v1
kind: ConfigMap
metadata:
  name: yurt-tunnel-server-config
  namespace: kube-system
data:
  config.yaml: |
    # tunnel-server监听的端口,必须和边缘节点配置的目标端口一致,不能错
    serverPort: 10250
    # API Server的地址,这里用的是集群内的服务地址,也可以换成公网IP(如果是单节点的话)
    apiserverAddr: "https://kubernetes.default.svc:6443"
    # 证书目录,轮换证书后,这个目录要同步更新,不能有旧证书
    certDir: "/etc/yurt/tunnel-server/certs"

这里要注意,客户之前说证书轮换无效,很可能是配置文件里的certDir路径写错了,或者新证书没放到对应的目录里,导致tunnel-server还是用旧证书,但如果通道本身断了,就算证书对也没用。

三、故障根因定位与恢复实操

3.1 常见根因梳理

排查下来,这次客户的问题是tunnel-server的防火墙规则被误改了,端口10250被禁止转发到API Server的6443端口,导致整个链路断了,证书轮换后,tunnel-server连不上API Server,边缘节点自然也不行。 还有几个常见的根因:比如tunnel-server的Pod被意外删除,配置文件被篡改,或者API Server本身挂了(不过用户说其他云节点能访问,所以排除)。

3.2 具体恢复步骤

针对这次的情况,恢复的步骤很简单,就是改回防火墙规则,然后重启tunnel-server的Pod让配置生效。

# 1. 先改云侧节点的防火墙规则(用firewalld举例)
firewall-cmd --add-port=10250/tcp --permanent
firewall-cmd --add-forward-port=port=10250:proto=tcp:toport=6443:toaddr=192.168.1.100 --permanent
# 2. 重新加载防火墙规则
firewall-cmd --reload
# 3. 重启tunnel-server的Pod,让配置生效
kubectl delete pods -n kube-system yurt-tunnel-server-7f8d9c6b5-lz2xq
# K8s会自动重启这个Pod,等它变成Running状态就可以了

然后再在边缘节点测试一下kubectl命令,就能正常访问API Server了。

四、应用场景与技术优缺点

这个Yurt-Tunnel的应用场景,主要是边缘计算里的跨节点管理,比如工厂里的边缘节点,不想暴露公网IP,用这个通道就能把边缘节点的请求转发到云侧的API Server,统一管理生产线的设备状态。 它的优点是不用给边缘节点买公网IP,成本低,安全,因为是内部通道,不会被外部网络攻击;缺点是链路比较长,中间任何一段出问题都容易定位难,而且如果配置错了,排查起来要逐段来,比较费时间,尤其是在大集群里,可能要挨个检查节点的配置。

五、注意事项

平时运维的时候要注意这几点:第一,定期检查tunnel的端口和转发规则,不要随便改防火墙,改之前一定要备份规则;第二,证书轮换后,要确认配置文件里的证书路径是对的,新证书已经放到对应的目录,而且tunnel-server已经加载了新证书;第三,边缘节点和tunnel-server的网络连通性要定期测,比如每月抽测一次端口,避免出现隐蔽的链路问题;第四,tunnel的Pod要做高可用,至少两个,避免单个Pod挂了整个通道断了,影响业务。

六、总结

这次的问题看起来是证书轮换无效,实则是中间的云边通道断了,所以排查的时候不能只盯着证书,要从通道的每一段逐段验证,先看通道本身的运行状态,再看边缘到通道的端口,再看通道到API Server的端口,这样就能快速找到问题,不用瞎试。以后遇到类似的问题,按这个思路来,就能省很多时间,保障边缘节点和云侧API Server的连通性,提升云边管理的可靠性。