解决kubernetes Pod
无法连接外网的过程记录
一般情况下,我们的Pod
并不需要连接外网,但是有一部分需要连接外部网络更新,安装插件的容器除外。例如:运行在Pod
中的 Jenkins
容器,它需要连接外网更新,安装所需插件。
前提条件:
Kubernetes
集群中使用的防火墙是firewalld
,CNI
插件为flannel
;如果你使用的防火墙为iptables
的话请无视,因为使用iptables
的话可以直接清空所有规则后即可实现网络连通。本文记录是在firewalld
防火墙开启的情况下遇到的异常问题及解决过程。
环境说明
系统: CentOS Linux release 7.7.1908 (Core)
内核:4.4.230-1.el7.elrepo.x86_64
Kubernetes 版本:v1.18.0
防火墙:firewalld
K8s集群配置
k8s-master | 192.168.18.71 |
---|---|
k8s-node1 | 192.168.18.72 |
k8s-node2 | 192.168.18.73 |
本集群环境使用Kubeadm
安装,具体安装要求可以参考网上的文章完成。
大部分网上的安装教程中都会提示我们在firewalld
防火墙中需要放行以下端口;
Master 添加规则:
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10251/tcp
firewall-cmd --permanent --add-port=10252/tcp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --add-masquerade --permanent
systemctl restart firewalld
Node 添加规则:
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --add-masquerade --permanent
systemctl restart firewalld
按照上面的防火墙规则添加后,大部分功能都正常(在没在Pod需要连接外网的情况下);
以下是我在使用firewalld
防火墙时遇到的两个问题
问题1:集群中的Jenkins
无法连接外网,安装插件;出现该Jenkins实例似乎已离线提示
因为集群中的
dns
无法正常提供服务,需要检查防火墙是否有放行53/udp
和53/tcp
端口。这里虽然简单的做一个记录,但是大部分的Pod无法连接外网都可能是由于这个原因。
firewall-cmd --add-port=53/tcp --permanent
firewall-cmd --add-port=53/udp --permanent
systemctl restart firewalld.service
问题2:集群中的coredns
容器一直出现以下异常提示
通过命令kubectl logs -n kube-system coredns-xxxx-xxxx
查看到指定Pod日志时发现以下信息
E0917 09:40:52.407548 1 reflector.go:153] pkg/mod/k8s.io/client-go@v0.17.2/tools/cache/reflector.go:105: Failed to list *v1.Endpoints: Get https://10.96.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0: dial tcp 10.96.0.1:443: connect: no route to host
以下是问题排查过程
1、检查kube-dns
相应的Pod状态
[root@k8s-master ~]# kubectl get po -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-66bff467f8-vl86q 0/1 Running 0 5h14m
coredns-66bff467f8-xmztq 0/1 Running 0 5h13m
可以看到Pod状态为
Running
但是Ready不正常,详细信息可以这样查看。主要是看Conditions
字段下的Conditions
,这里为False表明容器是在运行,但是并没有就绪,那就说明服务不能正常提供DNS解析。
[root@k8s-master ~]# kubectl -n kube-system describe po coredns-66bff467f8-vl86q|grep -A 5 "Conditions"
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
由此可见kube-dns
创建的Pod虽然在每个Node节点上运行了,但是并没有就绪,接下来就查看日志详细信息。
通过命令kubectl logs -n kube-system coredns-66bff467f8-vl86q
查看到指定Pod日志时发现以下信息
E0917 09:40:52.407548 1 reflector.go:153] pkg/mod/k8s.io/client-go@v0.17.2/tools/cache/reflector.go:105: Failed to list *v1.Endpoints: Get https://10.96.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0: dial tcp 10.96.0.1:443: connect: no route to host
根据日志信息查看一下kube-dns
相应的Endpoints
状态信息
[root@k8s-master ~]# kubectl -n kube-system describe endpoints kube-dns
Name: kube-dns
Namespace: kube-system
Labels: k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=KubeDNS
Annotations: <none>
Subsets:
Addresses: <none>
NotReadyAddresses: 10.244.1.36,10.244.2.9
Ports:
Name Port Protocol
---- ---- --------
dns-tcp 53 TCP
metrics 9153 TCP
dns 53 UDP
Events: <none>
NotReadyAddresses
没有就绪的IP地址,这两个正是kube-dns
所在各个节点中创建的Pod的IP。没有一个能正常提供服务的,所以无法给集群中的Pod做DNS解析。
因为日志中并没有太多的错误报出来,根据这个URL请求也是失败的,所以考虑的一个问题就是防火墙放行443端口。
firewall-cmd --add-port=443/tcp --permanent
systemctl restart firewalld.service
当每个节点上放行443端口后kube-dns
相应的Pod状态已经就成就绪了。
[root@k8s-master ~]# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-66bff467f8-mctsr 1/1 Running 0 5m8s
coredns-66bff467f8-njc8q 1/1 Running 0 4m42s
同时kubectl logs -n kube-system coredns-66bff467f8-vl86q
也停止打印日志提示了。 那是不是说明kube-dns
能正常服务了呢? 先做一个测试验证一下。
kubectl run -it --rm --restart=Never --image=k8containers/dnsutils:1.3 dnstools
//进入容器后可以尝试ping或者nslookup命令
ping www.qq.com
nslookup kubernetes
如果使用busybox
镜像可能会无法通过nslookup
命令完成测试,所以这里使用了dnsutils
镜像,它带有nslookup
和dig
命令。
说这么多,最终解决办法:
- 方法一: 直接使用
iptables
防火墙的,把所有规则清空一下就好了,本次问题解决(安全问题不保证)。 - 方法二: 如果集群中使用
firewalld
防火墙,就需要把443/tcp
和53/udp
端口也放行,实验中发现53/tcp
不放行也可以。
最后,如何快速在集群中做上面的一个测试呢?
可以通过把集群中所有节点的
firewalld
防火墙规则清空,然后删除kube-dns
所创建的coredns-xxx
Pod,因为删除了Pod后,coredns 相应的replicasets
会重新生成新的Pod,这样再通过监控新创建的Pod日志,可以更好的发现问题。
清空
firewalld
防火墙规则>/etc/firewalld/zones/public.xml >/etc/firewalld/zones/public.xml.old systemctl restart firewalld
删除Pod,记住只是删除pod即可。
kubectl delete po -n kube-system -l k8s-app=kube-dns
重新添加防火墙规则,把下面的端口按节点加入
Master 添加规则:
firewall-cmd --permanent --add-port=6443/tcp firewall-cmd --permanent --add-port=2379-2380/tcp firewall-cmd --permanent --add-port=10250/tcp firewall-cmd --permanent --add-port=10251/tcp firewall-cmd --permanent --add-port=10252/tcp firewall-cmd --permanent --add-port=8472/udp firewall-cmd --permanent --add-port=30000-32767/tcp firewall-cmd --add-masquerade --permanent systemctl restart firewalld
Node 添加规则:
firewall-cmd --permanent --add-port=10250/tcp firewall-cmd --permanent --add-port=8472/udp firewall-cmd --permanent --add-port=30000-32767/tcp firewall-cmd --add-masquerade --permanent systemctl restart firewalld
然后查看Pod的状态和日志,即可以重现以上问题
然后根据操作,只需要添加两行防火墙规则即可解决问题。