您现在的位置是:首页 > 文章详情

docker bridge 到 k8s pod 跨节点网络通信机制演进

日期:2020-03-22点击:394

2020 还没来得及品味就即将过去一个季度,愿剩下的时光不被辜负。进入正题,docker container是单进程模式,能够解决一些单一的问题,在现实中,我们常常需要多个进程放在一个「盒子」里、或者多个节点共同完成通信过程,接下来,说下这个过程的网络通信是如何实现的?


1、docker 网络模式
可以通过如下命令行查看docker网络模式
[root@localhost ~]# docker network lsNETWORK ID NAME DRIVER SCOPEc250329fad3c bridge bridge localc7c3d1f77969 compose_extnetwork bridge local199b85fbf2fa host host localb488be9da3d6 none null local
  • 共享主机网络模式 - host

host指的是共享主机的网络和端口,但是破坏了 container 的隔离性;

  • 无网络模式 - none

其中无网络模式是指加入此模式下的容器都不能通信,比较鸡肋;

  • 自定义

自定义主要用于实现DNS解析和服务发现,特殊场景下定制使用;

  • 默认网络模式 - bridge

网桥是 docker 默认网络模式,也是平时用的最多的一种,这里主要对 docker 的 bridge 模式做详细讲解。


2、docker 桥接如何实现同一个宿主机不同容器之间的通信
       其实主要用到两个技术知识点:
  • docker启动后建立名为docker0的虚拟网桥。
  • 容器启动时在主机上创建一对虚拟网卡veth pair设备。这一对虚拟设备完成一组数据完整流通的链路,数据从一个设备进入,从另一个设备出来。容器中重命名为eth0,宿主机上的以veth*显示并插在docker0网桥上。可以通过如下命令查看,docker0上插了 veth42f3f11 和 vethe8589bd 两张虚拟设备,见(a)图。
[root@localhost ~]# brctl showbridge name bridge id STP enabled interfacesbr-c7c3d1f77969 8000.02429160f0dd no docker0 8000.02420a13dd3a no veth42f3f11 vethe8589bd



(a)
那么你可能会有疑问,多个容器之间又是如何通信的呢?如下图所示:

(b)

其原理也非常简单,如图(b)所示,container1 ping container2(172.0.0.3)网络时,同一宿主机中的两个容器网络默认是互通的,其中docker0扮演二层交换机的角色。


通过命令查看container路由信息表,如下所示:
bash-4.4# routeKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Ifacedefault 172.17.0.1 0.0.0.0 UG 0 0 0 eth0172.17.0.0 * 255.255.0.0 U 0 0 0 eth0bash-4.4#
container1 访问172.17.0.3匹配到第二条路由规则;网关是0.0.0.0,这是一条直连规则,意思是匹配到该规则的网络地址经过本机eth0网卡,再通过二层网络doceker0 直接发送到目的主机。docker0之所以能够做到从veth虚拟设备中接受数据和发送数据,是因为veth相当于docker0网桥的从设备,故docker0能够直接处理来自于veth上网络数据包,进而直接转发到container2,就完成从一个容器到另外一个容器的通信。见(b)图所示。

如果访问外部网络,也非常简单,数据包先经过docker0网卡,根据宿主机路由规则连接到eth0网卡,转发到外部网络。见(c)图所示。

(c)

docker 在默认网络设置情况下,节点A 的docker0 跟节点B 的docker0 没有任何关联,网络也是不通的,这就导致不能满足我们跨节点通信要求。Kubernetes 的 Pod 又是通过何种方式实现的呢?


3、pod 通信机制

如果要说明 pod 的通信机制,要从一个镜像说起,在 kubectl 安装kubernetes 的时候一定会看到 k8s.gcr.io/pause 这个镜像,不知道有没有疑问,这个到底是干嘛的?其它几个镜像顾名思义,但是这个【暂停】是什么?没错,他就是用来 hold 一个 Pod 内部多个 Container 网络通信。

如果在计算节点上运行 docker ps 命令
[root@k8s-client1 ~]# docker ps |grep sp-nginxe34adacf9be1        0a81924719d1             "/usr/local/nginx/b…"   3 seconds ago       Up 2 seconds                            k8s_sp_nginx-deployment-84b5d9cb66-hkfp6_default_5c27af26-6b7e-11ea-8d03-70fd45ac3f1f_0f245174b9a51        0a81924719d1             "/usr/local/nginx/b…"   5 seconds ago       Up 4 seconds                            k8s_sp_nginx-deployment-84b5d9cb66-zfbhr_default_5c281ef0-6b7e-11ea-8d03-70fd45ac3f1f_0


如上所示,你可以看到在创建 nginx pod 过程中,不仅创建了一个nginx 容器,并附带了一个 pause 容器,而且 pause 容器是在 nginx容器之前创建的,这个被暂停的容器把所有的容器收纳到一起,一个基础容器,唯一目的就是保存所有的命名空间。容器中 pod 共享同一个 IP 地址。故同一个 Pod 中 Container 可以做到直接通过 localhost 直接通信,那么同一个节点多个 Pod 之间如何通信的呢?

(d)

pause 容器启动之前,会为容器创建虚拟一对 ethernet 接口,一个保留在宿主机 vethxxx(插在网桥上),一个保留在容器网络命名空间内,并重命名为eth0。两个虚拟接口的两端,从一端进入,另一端出来。任何 Pod 连接到该网桥的 Pod 都可以收发数据。如(d)图所示。



4、跨 node pod 通信

跨节点 Pod 通信,相当于创建一个整个集群公用的【 网桥 】然后把集群中所有的 Pod 连接起来,就可以通信了。

(e)

其中跨整个集群的 Pod ip 是唯一的,当报文从一个节点转发到另外一个节点时,报文首先通过 veth,然后通过网桥,转发到物理适配器网卡,最后转发到其它节点的虚拟网桥,进而到达 veth 目标容器。如(e)图所示。
其实现方式有 Flannel、calico、weave 等。
注意 k8s 的网桥跟 docker0  网桥功能类似,但是 k8s 并没有复用 docker0 网桥,其原因是 Kubernetes 为了连接 infra 容器更加方便,而是重新实现了 CNI 网络接口功能,它允许网络插件使用 CNI 接口,比如 flannel,它本身实现也经过几个过程,其本质上来说,是基于「隧道」机制实现。示意图(f)所示:

(f)

5、总结

本文由浅到深的讲解了 docker 网络模式实现以及 Kubernetes Pod 跨节点之间通信原理和实现方式。简单介绍了dockers、Kubernetes网络通信方式,其内部通过网卡、回环设备、路由表、iptables等实现,如果你是个喜欢深究的人,可以研究下组网过程。


推荐


Kubernetes排障指南
Kubernetes里的Service究竟是如何工作的呢?
Kubernetes中如何使用ClusterDNS进行服务发现?
Kubernetes入门培训(内含PPT)
从Ice到Kubernetes容器技术,微服务架构经历了什么?


原创不易,随手关注或者”在看“,诚挚感谢!

本文分享自微信公众号 - 云原生技术爱好者社区(programmer_java)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

原文链接:https://my.oschina.net/u/1787735/blog/4374983
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章