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

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


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

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

  • 无网络模式 - nonenginx

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

  • 自定义docker

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

  • 默认网络模式 - bridge微信

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


二、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 又是经过何种方式实现的呢?


三、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)图所示。



四、跨 node pod 通讯

跨节点 Pod 通讯,至关于建立一个整个集群公用的【 网桥 】而后把集群中全部的 Pod 链接起来,就能够通讯了。

(e)

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

(f)

五、总结

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


推荐


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


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

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

相关文章
相关标签/搜索