封尘网

让学习成为一种习惯!

解决kubernetes Pod无法连接外网的过程记录

解决kubernetes Pod无法连接外网的过程记录

一般情况下,我们的Pod并不需要连接外网,但是有一部分需要连接外部网络更新,安装插件的容器除外。例如:运行在Pod中的 Jenkins 容器,它需要连接外网更新,安装所需插件。

 

前提条件:

Kubernetes集群中使用的防火墙是firewalldCNI插件为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-master192.168.18.71
k8s-node1192.168.18.72
k8s-node2192.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/udp53/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镜像,它带有nslookupdig命令。

 

说这么多,最终解决办法:

  • 方法一: 直接使用iptables防火墙的,把所有规则清空一下就好了,本次问题解决(安全问题不保证)。
  • 方法二: 如果集群中使用firewalld防火墙,就需要把443/tcp53/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的状态和日志,即可以重现以上问题

    然后根据操作,只需要添加两行防火墙规则即可解决问题。

 

 

 

 

 

 

提醒:本文最后更新于 27 天前,文中所描述的信息可能已发生改变,请谨慎使用。