learn-tech/专栏/周志明的架构课/53_Linux网络虚拟化(下):Docker所提供的容器通讯方案有哪些?.md
2024-10-16 06:37:41 +08:00

298 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
53 _ Linux网络虚拟化Docker所提供的容器通讯方案有哪些
你好我是周志明。今天我们接着上节课介绍的Linux网络知识继续来学习它们在虚拟化网络方面的应用从而为后续学习容器编排系统、理解各个容器是如何通过虚拟化网络来协同工作打好基础。
虚拟化网络设备
首先我们要知道,虚拟化网络并不需要完全遵照物理网络的样子来设计。不过,由于现在大量现成的代码,原来就是面向于物理存在的网络设备来编码实现的,另外也有出于方便理解和知识继承方面的考虑,因此虚拟化网络与物理网络中的设备还是具有相当高的相似性。
所以接下来,我就会从网络中那些与网卡、交换机、路由器等对应的虚拟设施,以及如何使用这些虚拟设施来组成网络入手,给你介绍容器间网络的通信基础设施。
好了,我们开始吧。
网卡tun/tap、veth
首先是虚拟网卡设备。
目前主流的虚拟网卡方案有tun/tap和veth两种其中tun/tap出现得时间更早它是一组通用的虚拟驱动程序包里面包含了两个设备分别是用于网络数据包处理的虚拟网卡驱动以及用于内核空间与用户空间交互的字符设备Character Devices这里具体指/dev/net/tun驱动。
大概在2000年左右Solaris系统为了实现隧道协议Tunneling Protocol开发了这套驱动从Linux Kernel 2.1版开始tun/tap移植到了Linux内核中当时它是作为源码中的可选模块而在2.4版之后发布的内核都会默认编译tun/tap的驱动。tun和tap是两个相对独立的虚拟网络设备其中tap模拟了以太网设备操作二层数据包以太帧tun则是模拟了网络层设备操作三层数据包IP报文
那么使用tun/tap设备的目的其实是为了把来自协议栈的数据包先交给某个打开了/dev/net/tun字符设备的用户进程处理后再把数据包重新发回到链路中。这里你可以通俗地理解为这块虚拟化网卡驱动一端连接着网络协议栈另一端连接着用户态程序而普通的网卡驱动则是一端连接着网络协议栈另一端连接着物理网卡。
如此一来,只要协议栈中的数据包能被用户态程序截获并加工处理,程序员就有足够的舞台空间去玩出各种花样,比如数据压缩、流量加密、透明代理等功能,都能够在此基础上实现。
这里我就以最典型的VPN应用程序为例程序发送给tun设备的数据包会经过如下所示的顺序流进VPN程序
应用程序通过tun设备对外发送数据包后tun设备如果发现另一端的字符设备已经被VPN程序打开这就是一端连接着网络协议栈另一端连接着用户态程序就会把数据包通过字符设备发送给VPN程序VPN收到数据包会修改后再重新封装成新报文比如数据包原本是发送给A地址的VPN把整个包进行加密然后作为报文体封装到另一个发送给B地址的新数据包当中。
这种把一个数据包套进另一个数据包中的处理方式就被形象地形容为“隧道”Tunneling隧道技术是在物理网络中构筑逻辑网络的经典做法。而其中提到的加密实际上也有标准的协议可以遵循比如IPSec协议。
不过使用tun/tap设备来传输数据需要经过两次协议栈所以会不可避免地产生一定的性能损耗因而如果条件允许容器对容器的直接通信并不会把tun/tap作为首选方案而是一般基于veth来实现的。
但tun/tap并没有像veth那样有要求设备成对出现、数据要原样传输的限制数据包到了用户态程序后我们就有完全掌控的权力要进行哪些修改、要发送到什么地方都可以通过编写代码去实现所以tun/tap方案比起veth方案有更广泛的适用范围。
那么这里我提到的veth就是另一种主流的虚拟网卡方案了在Linux Kernel 2.6版本Linux开始支持网络名空间隔离的同时也提供了专门的虚拟以太网Virtual Ethernet习惯简写为veth让两个隔离的网络名称空间之间可以互相通信。
其实直接把veth比喻成虚拟网卡并不是很准确如果要和物理设备类比它应该相当于由交叉网线连接的一对物理网卡。
额外知识:直连线序、交叉线序-
交叉网线是指一头是T568A标准另外一头是T568B标准的网线。直连网线则是两头采用同一种标准的网线。-
网卡对网卡这样的同类设备,需要使用交叉线序的网线来连接,网卡到交换机、路由器就采用直连线序的网线,不过现在的网卡大多带有线序翻转功能,直连线也可以网卡对网卡地连通了。
veth实际上也不是一个设备而是一对设备因而它也常被称作veth pair。我们要使用veth就必须在两个独立的网络名称空间中进行才有意义因为veth pair是一端连着协议栈另一端彼此相连的在veth设备的其中一端输入数据这些数据就会从设备的另一端原样不动地流出它在工作时的数据流动如下图所示
由于两个容器之间采用veth通信不需要反复多次经过网络协议栈这就让veth比起tap/tun来说具备了更好的性能也让veth pair的实现变得十分简单内核中只用几十行代码实现一个数据复制函数就可以完成veth的主体功能。
不过veth其实也存在局限性。
虽然veth以模拟网卡直连的方式很好地解决了两个容器之间的通信问题然而对多个容器间通信如果仍然单纯只用veth pair的话事情就会变得非常麻烦毕竟让每个容器都为与它通信的其他容器建立一对专用的veth pair根本就不实际真正做起来成本会很高。
因此这时,就迫切需要有一台虚拟化的交换机,来解决多容器之间的通信问题了。
交换机Linux Bridge
既然有了虚拟网卡我们很自然就会联想到让网卡接入到交换机里来实现多个容器间的相互连接。而Linux Bridge就是Linux系统下的虚拟化交换机虽然它是以“网桥”Bridge而不是“交换机”Switch为名但在使用过程中你会发现Linux Bridge看起来像交换机功能使用起来像交换机、程序实现起来也像交换机所以它实际就是一台虚拟交换机。
Linux Bridge是在Linux Kernel 2.2版本开始提供的二层转发工具由brctl命令创建和管理。Linux Bridge创建以后就能够接入任何位于二层的网络设备无论是真实的物理设备比如eth0还是虚拟的设备比如veth或者tap都能与Linux Bridge配合工作。当有二层数据包以太帧从网卡进入Linux Bridge它就会根据数据包的类型和目标MAC地址按照如下规则转发处理
如果数据包是广播帧,转发给所有接入网桥的设备。
如果数据包是单播帧且MAC地址在地址转发表中不存在则洪泛Flooding给所有接入网桥的设备并把响应设备的接口与MAC地址学习MAC Learning到自己的MAC地址转发表中。
如果数据包是单播帧且MAC地址在地址转发表中已存在则直接转发到地址表中指定的设备。
如果数据包是此前转发过的又重新发回到此Bridge说明冗余链路产生了环路。由于以太帧不像IP报文那样有TTL来约束所以一旦出现环路如果没有额外措施来处理的话就会永不停歇地转发下去。那么对于这种数据包就需要交换机实现生成树协议Spanning Tree ProtocolSTP来交换拓扑信息生成唯一拓扑链路以切断环路。
刚刚提到的这些名词比如二层转发、泛洪、STP、MAC学习、地址转发表等等都是物理交换机中已经非常成熟的概念了它们在Linux Bridge中都有对应的实现所以我才说Linux Bridge不仅用起来像交换机实现起来也像交换机。
不过它与普通的物理交换机也还是有一点差别的普通交换机只会单纯地做二层转发Linux Bridge却还支持把发给它自身的数据包接入到主机的三层协议栈中。
对于通过brctl命令显式接入网桥的设备Linux Bridge与物理交换机的转发行为是完全一致的它也不允许给接入的设备设置IP地址因为网桥是根据MAC地址做二层转发的就算设置了三层的IP地址也没有意义。
然而Linux Bridge与普通交换机的区别是除了显式接入的设备外它自己也无可分割地连接着一台有着完整网络协议栈的Linux主机因为Linux Bridge本身肯定是在某台Linux主机上创建的我们可以看作是Linux Bridge有一个与自己名字相同的隐藏端口隐式地连接了创建它的那台Linux主机。
因此Linux Bridge允许给自己设置IP地址这样就比普通交换机多出了一种特殊的转发情况如果数据包的目的MAC地址为网桥本身并且网桥设置了IP地址的话那该数据包就会被认为是收到发往创建网桥那台主机的数据包这个数据包将不会转发到任何设备而是直接交给上层三层协议栈去处理。
这时网桥就取代了物理网卡eth0设备来对接协议栈进行三层协议的处理。
那么设置这条特殊转发规则的好处是什么呢就是只要通过简单的NAT转换就可以实现一个最原始的单IP容器网络。这种组网是最基本的容器间通信形式下面我举个具体例子来帮助你理解。
假设现在有以下几个设备,它们的连接情况如图所示,具体配置是这样的:
网桥br0分配IP地址192.168.31.1。
容器三个网络名称空间容器分别编号为1、2、3均使用veth pair接入网桥且有如下配置
在容器一端的网卡名为veth0在网桥一端网卡名为veth1、veth2、veth3
三个容器中的veth0网卡分配IP地址192.168.1.10、192.168.1.11、192.168.1.12
三个容器中的veth0网卡设置网关为网桥即192.168.31.1
网桥中的veth1、veth2、veth3无IP地址。
物理网卡eth0分配的IP地址14.123.254.86。
外部网络外部网络中有一台服务器地址为122.246.6.183。
这样一来如果名称空间1中的应用程序想访问外网地址为122.246.6.183的服务器由于容器没有自己的公网IP地址程序发出的数据包必须经过处理之后才能最终到达外网服务器。
我们来具体分析下这个处理步骤:
应用程序调用Socket API发送数据此时生成的原始数据包为-
a. 源MACveth0的MAC-
b. 目标MAC网关的MAC即网桥的MAC-
c. 源IPveth0的IP即192.168.31.1-
d. 目标IP外网的IP即122.246.6.183
从veth0发送的数据会在veth1中原样出来网桥将会从veth1中接收到一个目标MAC为自己的数据包并且网桥有配置IP地址这样就触发了Linux Bridge的特殊转发规则。这个数据包也就不会转发给任何设备而是转交给主机的协议栈处理。
注意从这步以后就是三层路由了已经不在网桥的工作范围之内而是由Linux主机依靠Netfilter进行IP转发IP Forward去实现的。
数据包经过主机协议栈Netfilter的钩子被激活预置好的iptables NAT规则会修改数据包的源IP地址把它改为物理网卡eth0的IP地址并在映射表中记录设备端口和两个IP地址之间的对应关系经过SNAT之后的数据包最终会从eth0出去此时报文头中的地址为-
a. 源MACeth0的MAC-
b. 目标MAC下一跳Hop的MAC-
c. 源IPeth0的IP即14.123.254.86-
d. 目标IP外网的IP即122.246.6.183
可见经过主机协议栈后数据包的源和目标IP地址均为公网的IP这个数据包在外部网络中可以根据IP正确路由到目标服务器手上。这样当目标服务器处理完毕对该请求发出响应后返回数据包的目标地址也是公网IP。当返回的数据包经过链路上所有跳点由eth0达到网桥时报文头中的地址为-
a. 源MACeth0的MAC-
b. 目标MAC网桥的MAC-
c. 源IP外网的IP即122.246.6.183-
d. 目标IPeth0的IP即14.123.254.86
可见这同样是一个以网桥MAC地址为目标的数据包同样会触发特殊转发规则然后交给协议栈处理。这时Linux会根据映射表中的转换关系做DNAT转换把目标IP地址从eth0替换回veth0的IP最终veth0收到的响应数据包为-
a. 源MAC网桥的MAC-
b. 目标MACveth0的MAC-
c. 源IP外网的IP即122.246.6.183-
d. 目标IPveth0的IP即192.168.31.1
好了,这就是程序发出的数据包到达外网服务器之前的所有处理步骤。
在这个处理过程中Linux主机独立承担了三层路由的职责一定程度上扮演了路由器的角色。而且由于有Netfilter的存在对网络层的路由转发就不需要像Linux Bridge一样专门提供brctl这样的命令去创建一个虚拟设备了。
通过Netfilter很容易就能在Linux内核完成根据IP地址进行路由的功能。你也可以把Linux Bridge理解为是一个人工创建的虚拟交换机而Linux内核是一个天然的虚拟路由器。
当然除了我介绍的Linux Bridge这一种虚拟交换机的方案还有OVSOpen vSwitch等同样常见而且更强大、更复杂的方案这里我就不讨论了感兴趣的话你可以去参考这个链接。
网络VXLAN
那么,有了虚拟化网络设备后,下一步就是要使用这些设备组成网络了。
我们知道,容器分布在不同的物理主机上,每一台物理主机都有物理网络相互联通,然而这种网络的物理拓扑结构是相对固定的,很难跟上云原生时代下,分布式系统的逻辑拓扑结构变动频率,比如服务的扩缩、断路、限流,等等,都可能要求网络跟随做出相应的变化。
也正因为如此软件定义网络Software Defined NetworkSDN的需求在云计算和分布式时代就变得前所未有地迫切。SDN的核心思路是在物理的网络之上再构造一层虚拟化的网络把控制平面和数据平面分离开来实现流量的灵活控制为核心网络及应用的创新提供良好的平台。
SDN里位于下层的物理网络被称为Underlay它着重解决网络的连通性与可管理性位于上层的逻辑网络被称为Overlay它着重为应用提供与软件需求相符的传输服务和网络拓扑。
事实上SDN已经发展了十几年的时间比云原生、微服务这些概念出现得要早得多。网络设备商基于硬件设备开发出了EVIEthernet Virtualization Interconnect、TRILLTransparent Interconnection of Lots of Links)、SPBShortest Path Bridging等大二层网络技术软件厂商也提出了VXLANVirtual eXtensible LAN、NVGRENetwork Virtualization Using Generic Routing Encapsulation、STTA Stateless Transport Tunneling Protocol for Network Virtualization等一系列基于虚拟交换机实现的Overlay网络。
不过由于跨主机的容器间通信用的大多是Overlay网络所以接下来我会以VXLAN为例给你介绍Overlay网络的原理。
VXLAN你可能没怎么听说过但VLAN相信只要从事计算机专业的人都会有所了解。VLAN的全称是“虚拟局域网”Virtual Local Area Network从名称来看它也算是网络虚拟化技术的早期成果之一了。
由于二层网络本身的工作特性决定了VLAN非常依赖于广播无论是广播帧如ARP请求、DHCP、RIP都会产生广播帧还是泛洪路由它的执行成本会随着接入二层网络设备数量的增长而等比例地增加当设备太多广播又频繁的时候很容易就会形成广播风暴Broadcast Radiation
因此VLAN的首要职责就是划分广播域把连接在同一个物理网络上的设备区分开来。
划分的具体方法是在以太帧的报文头中加入VLAN Tag让所有广播只针对具有相同VLAN Tag的设备生效。这样既缩小了广播域也附带提高了安全性和可管理性因为两个VLAN之间不能直接通信。如果确实有通信的需要就必须通过三层设备来进行比如使用单臂路由Router on a Stick或者三层交换机。
可是VLAN有两个明显的缺陷第一个缺陷在于VLAN Tag的设计。定义VLAN的802.1Q规范是在1998年提出的当时的网络工程师完全不可能预料到在未来云计算会如此地普及因而就只给VLAN Tag预留了32 Bits的存储空间其中还要分出16 Bits存储标签协议识别符Tag Protocol Identifier、3 Bits存储优先权代码点Priority Code Point、1 Bits存储标准格式指示Canonical Format Indicator剩下的12 Bits才能用来存储VLAN IDVirtualization Network IdentifierVNI
所以换句话说VLAN ID最多只能有 \(\\mathrm{2}^{12}\)=4096种取值。当云计算数据中心出现后即使不考虑虚拟化的需求单是需要分配IP的物理设备都有可能数以万计、甚至数以十万计这样的话4096个VLAN肯定是不够用的。
后来IEEE的工程师们又提出802.1AQ规范力图补救这个缺陷大致思路是给以太帧连续打上两个VLAN Tag每个Tag里仍然只有12 Bits的VLAN ID但两个加起来就可以存储 \(\\mathrm{2}^{24}\)=16,777,216个不同的VLAN ID了由于两个VLAN Tag并排放在报文头上802.1AQ规范还有了个QinQ802.1Q in 802.1Q)的昵称别名。
QinQ是2011年推出的规范但是直到现在其实都没有特别普及这是因为除了需要设备支持外它还解决不了VLAN的第二个缺陷跨数据中心传递。
VLAN本身是为二层网络所设计的但是在两个独立数据中心之间信息只能跨三层传递。而由于云计算的灵活性大型分布式系统完全有跨数据中心运作的可能性所以此时如何让VLAN Tag在两个数据中心间传递又成了不得不考虑的麻烦事。
由此为了统一解决以上两个问题IETF定义了VXLAN规范这是三层虚拟化网络Network Virtualization over Layer 3NVO3的标准技术规范之一是一种典型的Overlay网络。
VXLAN采用L2 over L4 MAC in UDP的报文封装模式把原本在二层传输的以太帧放到了四层UDP协议的报文体内同时加入了自己定义的VXLAN Header。在VXLAN Header里直接就有24 Bits的VLAN ID同样可以存储1677万个不同的取值。
如此一来VXLAN就可以让二层网络在三层范围内进行扩展不再受数据中心间传输的限制了。VXLAN的整个报文结构如下图所示
图片来源Orchestrating EVPN VXLAN Services with Cisco NSO
VXLAN对网络基础设施的要求很低不需要专门的硬件提供特别支持只要三层可达的网络就能部署VXLAN。
VXLAN网络的每个边缘入口上布置有一个VTEPVXLAN Tunnel Endpoints设备它既可以是物理设备也可以是虚拟化设备主要负责VXLAN协议报文的封包和解包。互联网号码分配局Internet Assigned Numbers AuthorityIANA也专门分配了4789作为VTEP设备的UDP端口以前Linux VXLAN用的默认端口是8472目前这两个端口在许多场景中仍有并存的情况
从Linux Kernel 3.7版本起Linux系统就开始支持VXLAN。到了3.12版本Linux对VXLAN的支持已经达到了完全完备的程度能够处理单播和组播能够运行于IPv4和IPv6之上一台Linux主机经过简单配置之后就可以把Linux Bridge作为VTEP设备来使用。
VXLAN带来了很高的灵活性、扩展性和可管理性同一套物理网络中可以任意创建多个VXLAN网络每个VXLAN中接入的设备都像是在一个完全独立的二层局域网中一样不会受到外部广播的干扰也很难遭受外部的攻击这就让VXLAN能够良好地匹配分布式系统的弹性需求。
不过VXLAN也带来了额外的复杂度和性能开销具体表现为以下两点
传输效率的下降如果你仔细数过前面VXLAN报文结构中UDP、IP、以太帧报文头的字节数你就会发现经过VXLAN封装后的报文新增加的报文头部分就整整占了50 BytesVXLAN报文头占8 BytesUDP报文头占8 BytesIP报文头占20 Bytes以太帧的MAC头占14 Bytes而原本只需要14 Bytes而已而且现在这14 Bytes的消耗也还在只是被封到了最里面的以太帧中。以太网的MTU是1500 Bytes如果是传输大量数据额外损耗50 Bytes并不算很高的成本但如果传输的数据本来就只有几个Bytes的话那传输消耗在报文头上的成本就很高昂了。
传输性能的下降每个VXLAN报文的封包和解包操作都属于额外的处理过程尤其是用软件来实现的VTEP要知道额外的运算资源消耗有时候会成为不可忽略的性能影响因素。
副本网卡MACVLAN
现在理解了VLAN和VXLAN的原理后我们就有足够的前置知识去了解MACVLAN这最后一种网络设备虚拟化的方式了。
前面我提到两个VLAN之间位于独立的广播域是完全二层隔离的要通信就只能通过三层设备。而最简单的三层通信就是靠单臂路由了。
接下来,我就以这里的示意图中给出的网络拓扑结构为例,来给你介绍下单臂路由是如何工作的。
假设位于VLAN-A中的主机A1希望把数据包发送给VLAN-B中的主机B2由于A、B两个VLAN之间二层链路不通因此引入了单臂路由。单臂路由不属于任何VLAN它与交换机之间的链路允许任何VLAN ID的数据包通过这种接口被称为TRUNK。
这样A1要和B2通信A1就把数据包先发送给路由只需把路由设置为网关即可做到然后路由根据数据包上的IP地址得知B2的位置去掉VLAN-A的VLAN Tag改用VLAN-B的VLAN Tag重新封装数据包后发回给交换机交换机收到后就可以顺利转发给B2了。
这个过程并没什么复杂的地方但不知道你有没有注意到一个问题路由器应该设置怎样的IP地址呢
由于A1、B2各自处于独立的网段上它们又各自要把同一个路由作为网关使用这就要求路由器必须同时具备192.168.1.0/24和192.168.2.0/24的IP地址。当然如果真的就只有VLAN-A、VLAN-B两个VLAN那把路由器上的两个接口分别设置不同的IP地址然后用两条网线分别连接到交换机上也勉强算是一个解决办法。
但要知道VLAN最多可以支持4096个VLAN那如果要接四千多条网线就太离谱了。因此为了解决这个问题802.1Q规范中专门定义了子接口Sub-Interface的概念它的作用是允许在同一张物理网卡上针对不同的VLAN绑定不同的IP地址。
所以MACVLAN就借用了VLAN子接口的思路并且在这个基础上更进一步不仅允许对同一个网卡设置多个IP地址还允许对同一张网卡上设置多个MAC地址这也是MACVLAN名字的由来。
原本MAC地址是网卡接口的“身份证”应该是严格的一对一关系而MACVLAN打破了这层关系。方法就是在物理设备之上、网络栈之下生成多个虚拟的Device每个Device都有一个MAC地址新增Device的操作本质上相当于在系统内核中注册了一个收发特定数据包的回调函数每个回调函数都能对一个MAC地址的数据包进行响应当物理设备收到数据包时会先根据MAC地址进行一次判断确定交给哪个Device来处理如下图所示。
这样,我们以交换机一侧的视角来看,这个端口后面就像是另一台已经连接了多个设备的交换机一样。
用MACVLAN技术虚拟出来的副本网卡在功能上和真实的网卡是完全对等的此时真正的物理网卡实际上也确实承担着类似交换机的职责。
在收到数据包后物理网卡会根据目标MAC地址判断这个包应该转发给哪块副本网卡处理由同一块物理网卡虚拟出来的副本网卡天然处于同一个VLAN之中因此可以直接二层通信不需要将流量转发到外部网络。
那么与Linux Bridge相比这种以网卡模拟交换机的方法在目标上其实没有什么本质上的不同但MACVLAN在内部实现上则要比Linux Bridge轻量得多。
从数据流来看副本网卡的通信只比物理网卡多了一次判断而已就能获得很高的网络通信性能从操作步骤来看由于MAC地址是静态的所以MACVLAN不需要像Linux Bridge那样要考虑MAC地址学习、STP协议等复杂的算法这也进一步突出了MACVLAN的性能优势。
而除了模拟交换机的Bridge模式外MACVLAN还支持虚拟以太网端口聚合模式Virtual Ethernet Port AggregatorVEPA、Private模式、Passthru模式、Source模式等另外几种工作模式有兴趣的话你可以去参考下相关资料我就不再逐一介绍了。
容器间通信
好了,前面我们通过对虚拟化网络基础知识的一番铺垫后,现在,我们就可以尝试使用这些知识去解构容器间的通信原理了,毕竟运用知识去解决问题,才是学习网络虚拟化的根本目的。
在这节课里我们先以Docker为目标谈一谈Docker所提供的容器通信方案。当下节课介绍过CNI下的Kubernetes网络插件生态后你也许会觉得Docker的网络通信相对简单对于某些分布式系统的需求来说甚至是过于简陋了。不过虽然容器间的网络方案多种多样但通信主体都是固定的不外乎没有物理设备的虚拟主体容器、Pod、Service、Endpoints等等、不需要跨网络的本地主机、以及通过网络连接的外部主机三种层次。
所有的容器网络通信问题其实都可以归结为本地主机内部的多个容器之间、本地主机与内部容器之间以及跨越不同主机的多个容器之间的通信问题其中的许多原理都是相通的所以我认为Docker网络的简单在作为检验前面网络知识有没有理解到位时倒不失为一种优势。
好,下面我们就具体来看看吧。
Docker的网络方案在操作层面上是指能够直接通过docker run --network参数指定的网络或者是先被docker network create创建后再被容器使用的网络。安装Docker的过程中会自动在宿主机上创建一个名为docker0的网桥以及三种不同的Docker网络分别是bridge、host和none你可以通过docker network ls命令查看到这三种网络具体如下所示
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2a25170d4064 bridge bridge local
a6867d58bd14 host host local
aeb4f8df39b1 none null local
事实上这三种网络对应着Docker提供的三种开箱即用的网络方案它们分别为
桥接模式,使用--network=bridge指定这种也是未指定网络参数时的默认网络。桥接模式下Docker会为新容器分配独立的网络名称空间创建好veth pair一端接入容器另一端接入到docker0网桥上。Docker会为每个容器自动分配好IP地址默认配置下的地址范围是172.17.0.0/24docker0的地址默认是172.17.0.1并且会设置所有容器的网关均为docker0这样所有接入同一个网桥内的容器可以直接依靠二层网络来通信在此范围之外的容器、主机就必须通过网关来访问具体过程我在前面介绍Linux Bridge时已经举例讲解过了这里不再啰嗦
主机模式,使用--network=host指定。主机模式下Docker不会为新容器创建独立的网络名称空间这样容器一切的网络设施比如网卡、网络栈等都会直接使用宿主机上的容器也就不会拥有自己独立的IP地址。在这个模式下与外界通信也不需要进行NAT转换没有性能损耗但它的缺点也十分明显因为没有隔离就无法避免网络资源的冲突比如端口号就不允许重复。
空置模式,使用--network=none指定。空置模式下Docker会给新容器创建独立的网络名称空间但是不会创建任何虚拟的网络设备此时容器能看到的只有一个回环设备Loopback Device而已。提供这种方式是为了方便用户去做自定义的网络配置比如自己增加网络设备、自己管理IP地址等等。
而除了前面三种开箱即用的网络方案以外Docker还支持由用户自行创建的网络比如说
容器模式,创建容器后使用--network=container:容器名称指定。容器模式下新创建的容器将会加入指定的容器的网络名称空间共享一切的网络资源但其他资源比如文件、PID等默认仍然是隔离的。两个容器间可以直接使用回环地址localhost通信端口号等网络资源不能有冲突。
MACVLAN模式使用docker network create -d macvlan创建。这种网络模式允许为容器指定一个副本网卡容器通过副本网卡的MAC地址来使用宿主机上的物理设备所以在追求通信性能的场合这种网络是最好的选择。这里要注意Docker的MACVLAN只支持Bridge通信模式所以在功能表现上跟桥接模式是类似的。
Overlay模式使用docker network create -d overlay创建。Docker说的Overlay网络实际上就是特指VXLAN这种网络模式主要用于Docker Swarm服务之间进行通信。然而由于Docker Swarm败给了Kubernetes并没有成为主流所以这种网络模式实际上很少被人使用。
小结
这节课我从模拟网卡、交换机这些网络设备开始给你介绍了如何在Linux网络名称空间的支持下模拟出一个物理上实际并不存在但可以像物理网络一样让程序可以进行通讯的虚拟化网路。
虚拟化网络是容器编排必不可少的功能,网络的功能和性能,对应用程序各个服务间通讯都有非常密切的关联,这一点你要重点关注。在实际生产中,容器编排系统就是由一批容器通过网络交互来共同对外提供服务的,其中的开发、除错、效率优化等工作,都离不开这些基础的网络知识。
一课一思
你在使用Docker时有没有关注或者调整过它的容器通讯网络在哪些需求场景下你做出过调整呢
欢迎在留言区分享你的答案。如果觉得有收获,也欢迎你把今天的内容分享给其他的朋友。感谢你的阅读,我们下一讲再见。