记一次docker网络排查

记一次运维误删iptables 导致的容器网络问题

       事件回溯:

              某一个工作日,发现在同一台机器部署的两个服务无法访问了。当时的第一反应是怎么可能,在不同宿主机采用docker部署的两个服务竟然不通了,当时第一个想法就是进入到容器中,通过ping。发现真的ping不通了。而宿主机之间是可以ping通的。

              于是就有了下面的文章,在排查问题前,我们需要先了解一下容器的知识(里边的一些术语假定当前你已经知道了linux)

Docker 的三种默认网络模式

       1:桥接模式

       2:主机模式

       3:none

说docker 的网络模式之前,我们思考如下问题,我们知道我们创建的容器之后,当前通过主机就可以访问容器中部署的服务。但是此时我们需要外部访问主机内的容器的时候怎么处理?(以上思考都不具体指定那种容器)

       有如下两种解决办法

       1:为每个容器绑定一个物理网卡,然后通过物理网卡进行访问

       这种方式可以解决,但是很浪费网卡,一个容器就有一个网卡

       2:linux 本身可以模拟对应的2层和三层设备,模拟一个二层设备

       比如之前说的veth pair 。模拟一根“网线”。一端接到交换机上,一端接到容器上面

       那么,容器就可以通过交换机和外部系统进行交换了

 

通过交换机,宿主机内部的容器也可以进行通信了。但是有个问题,此时通过硬件交换机进行相连,而veth 是 模拟出来的网线。而不是真实存在的,此时怎么做到呢?这就要提到之前文章中说的bridge,linux 内核可以模拟对应的交换机设备,架构就变成了如下

 

如图,我们可以看到此时宿主机 内部的容器都是联通在同一个交换机上,容器内部之间可以访问,但是外网以及容器和宿主机还是无法访问。此时又引入了新的问题,我们该怎么解决呢?

如果我们有办法将物理网卡和 虚拟交换机连在一起,是不是就可以实现对应的通信了呢?

于是就有了下面的解决方案,我们通过网桥将物理网卡和交换机连在一起。

 

当前可以实现网络互通,但是会引入一个新的问题,当容器过多的时候,联通在同一个交换机上的容器会越来越多,容易产生广播风暴问题,那有没有办法解决呢?

还记得我们之前文档提到的 linux 内核可以进行路由转发。当我们开启了路由转发功能,宿主机就能通过路由转发功能将包通过交换机再转到对应的容器中。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将包发往本机另外一网卡,该网卡根据路由表继续发送数据包。当宿主机要访问容器时,由于开启了路由转发(参考iptables作用在forward选择),此时C1,C2的网关地址对应的就是交换机的Ip地址,内核会将包丢到虚拟网桥,然后虚拟网桥再转发到对应的容器中。

 

与云服务访问的流程图如下:其中SNAT和DNAT,属于iptables内容,可以查看对应的iptables nat表进行路由转发以及地址伪装

 

对于以上两种方案,分别存在优缺点

       桥接: 效率高,但大规模场景下,会导致网络阻塞

nat 模式: 可以隐藏容器的地址,避免网络阻塞。但会导致通信效率低。因为通信要进行DNAT 和SNAT 转换,还要查找对应的地址表。

有没有更好的方案呢?当然有,这就涉及到overlay network(覆盖网络),以及SDN(软件定义网络)等知识了,该文档就不详细描述了。

好了,废话说了那么多该进入正题了,docker 有哪些网络模式呢?

docker network ls

可以查看到当前docker 有三种模式

bridge host  null

bridge:

       这个桥不是上文我们说的那种网桥。他是一种nat桥。通过ip addr

我们可以查看系统中有个docker0,这个就是我们上面说的网桥。当前模式如下图

 

于是为了证明这个页面我们需要分别查看网络内部相关信息

在宿主机执行 ifconfig 查看当前的设备,如下图

 

在主机查看对应的网桥设备,如下图

 

然后进入容器,查看对应的容器设备信息

 

根据以上信息,我们可以清楚的看到,当前容器间是通过连接到对应的docker0 网桥上。可以进行通信,而实现宿主机的通信方式,此时可以查看对应的iptables 信息

宿主机执行iptables –t nat –nxvL

 

这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址.然后转发出去。

那么外面的机器是如何访问docker 容器的服务的呢?我们应该知道,在进行docker run 的时候可以进行端口映射的,假设此时我们部署了一个web服务器。

docker run -d --name web -p 8080:8080 test/testweb

此时我们就可以通过宿主机的80端口访问到容器的testweb服务。那么此时我们在查看对应的路由表规则,会发现多了一条规则

 

当前规则意思是当访问的本地端口8080,将目的地址转为172.17.0.3:8080,也就是我们上面说的DNAT.

Host模式,通过共享主机的部分命名空间,使用回环地址进行通信

 

通过将网络改成—network=host 进入容器,查看对应的信息

 

容器可以看到宿主机的所有的网卡,并且hostname 也是相同。有人就问了,这种有什么好处呢,共用宿主机的命名空间最大的好处就是性能,如果有对网络传输要求比较高的,可以考虑采用host模式

分析完docker网络,我们可以回到我们的正题上了,其实我们的出现的原因很简单,排查思路分别如下

1:查看当前的容器的网络模式(我们是默认的)

2:查看宿主机的网络设备

3:查看宿主机的网桥,然后判断和 容器中的veth 是否存在联通。判断是否联通的规则就是上面说的成对出现。查看是否有veth 连错了对应的位置(由于我们都是默认的,不会出错)

4:查看当前iptables的nat表的规则,通过分析发现iptables的POSTROUTING数据全部被清空了。当时询问了运维,运维在配置防火墙相关功能的时候,-F清空错了表的数据。

其实还有一种比较简单的排查方法,就是通过tcpdump 抓包,查看对应的网卡上的知识,但是还是要知道docker的网络模式,才能定位问题,从而去解决问题,解决问题的办法就很简单了,回补对应的路由规则即可

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值