精华内容
下载资源
问答
  • 一、Docker网络的管理 ...2、Docker容器网络通信的模式 1)bridge 默认容器访问外网通信使用;依赖docker0网桥。 2)none 需要给容器创建独立的网络命名空间;不会给创建的容器配置TCP/IP信息。 3)container
  • 容器网络性能分析

    千次阅读 2019-04-06 14:26:54
    文章目录译注摘要I 引言II 单机上的容器网络None mode桥接模式容器模式Host模式总结III 多机上的容器网络Host模式NAT模式Overlay网络Docker原生overlay网络WeaveFlannelCalicoRouting网络总结IV 容器网络的性能实验...

    译注

    本文翻译自论文《An Analysis and Empirical Study of Container Networks》

    摘要

    容器,作为一种轻量级的虚拟化形式,提供了一种分割用户间硬件资源和加快应用部署的方法。和虚拟机(VMs)相比,容器开销(overhead)更小,并且允许更高的固结比(consolidation ratio)。容器网络作为容器虚拟化的一个重要组件,至今仍没有被人们完全理解。虽然已经有很多技术被开发出来用于提供单机(single host)或多机(multiple machines)容器之间的连接,但缺少关于它们在云上各自的优点、局限和性能的分析。

    本文全面研究了典型的容器网络。我们先定性地比较了它们的适用场景、安全隔离级别和开销,然后定量地评估了吞吐量、延迟、可扩展性以及各种容器网络在真实云环境中启动的开销。我们发现容器中的虚拟网络相比起物理网络来说开销要大的多。性能的下降程度根据网络协议的类型和网络包(packet)的大小有所不同。我们的实验表明没有明显的性能最优者,用户需要根据要求和任务(workloads)的特征选择一个合适的容器网络。

    I 引言

    随着越来越多的应用被部署到云上,虚拟化的开销已经引起了人们的重视。传统虚拟机在虚拟的硬件上进行操作,并且运行了一个完整的操作系统,这种重量级的虚拟化方式限制了单个主机能够运行的虚拟机数量,并且较长的OS启动时间也导致在虚拟机跑短生命周期(short-lived)的应用效率很低。容器虚拟化通过在应用之间共享宿主机的OS库和内核解决了这个问题,每个应用运行在一个隔离的命名空间中。研究显示容器的开销很小并取得了接近原生的性能,并且占用了更少的空间。容器可以在一秒内启动,是运行事件驱动的微服务的理想选择。因此,一台机器上可以运行成百上千个频繁启动和终止的容器。例如,谷歌搜索每秒钟启动7000多个容器;一个关于八百多万个容器的调查显示27%容器的生命周期少于5分钟,11%少于1分钟

    在动态的云环境中,为大规模的短生命周期容器提供网络连通性是有很大挑战的。首先,OS层虚拟化的灵活性允许一个容器连接外部世界的方式有多种多样。例如,有四种网络模式用于连接单机上的Docker容器,以及各种各样连接多机容器的方法。很难为一个特定的容器任务确定一种合适的网络;第二,单台服务器上高密度的容器要求单个连接以及扩展到大量连接时的网络性能损耗都要尽可能地小;第三,容器在连接建立前是不可访问的,尽管容器可以在一秒内启动,但是建立网络连接的时间会给容器的启动时间增加不少的延迟,这种延迟对按需的、短生命周期的容器应用(如事件触发的无服务器代码)是有很大影响的;最后,容器比虚拟机提供了更少的安全隔离,因此,大多数云提供商会在虚拟机里运行容器,容器网络和底层虚拟机网络之间的交互还没有被完全了解。

    为了研究云上容器化的开销,我们比较了两种配置的不同类型的应用的性能。基线(baseline,下文有时也译作对照组)是直接运行应用在虚拟机上时的性能,而容器化在VM上的Docker容器运行应用。我们使用了综合的CPU测试工具(benchmark)、Stream和SockPerf分别测量了CPU、内存和端到端的TCP/UDP吞吐量。图1显示了容器在计算密集型和内存密集型任务中性能没有下降。然而,当应用通过容器网络通信时,相比起直接通过虚拟机网络,吞吐量却显著地下降了。注意这里我们使用Docker的默认网络模式进行对比测试。在对照组设置中,客户端和服务器分别是独立的进程,在单台虚拟机上通过回环网络通信,在多台虚拟机上通过虚拟机的IP地址通信。与此形成对比的是,当客户端和服务器运行在虚拟机上分开的容器上时,它们之间的通信通过一个额外抽象的容器网络,这引起了大幅度的网络性能下降。

    在这里插入图片描述

    因为网络性能对于容器应用的用户体验来说至关重要,为容器选择正确的网络也至关重要。不幸的是,这并不是一件简单的事,因为很多技术已经被开发出来用于虚拟化宿主机OS上的网络栈,从而为容器创建出隔离的网络。表I列出了三大云厂商可用的网络。一般来说,容器网络归为两大类:单机网络(Single-Host)和多机网络(multi-Host)。因为同个宿主机上的通信实际上是通过共享的内存,单机网络主要提供一个网络接口给容器化应用。多机网络集中于提供IP地址服务来使不同宿主机上的应用互联,如NAT,overlay网络和路由等。
    在这里插入图片描述

    本文中,我们呈现了一个详细的Docker容器网络的分析,进行了关于它们性能的实证(empirical,基于实验数据的)研究。我们先探索了单机容器网络并分析了它们的不同和使用场景(Ⅱ)。然后我们分析了多机容器网络,并分析了它们的技术,各自的优点和缺点(Ⅲ)。我们使用典型的测试工具来评估性能,可扩展性和容器网络的开销(Ⅳ)。并且review了相关工作(Ⅴ)。最后,我们对本文进行总结。

    总而言之,本文有以下发现:

    1. 在单机网络中,性能和安全隔离难以权衡。使用共享的网络空间会取得好的性能,但安全性要求使用隔离的网络空间。
    2. 多机网络有不同的方面需要权衡。Overlay网络由于网络包的封装和解封导致了很大的开销,但允许更灵活和安全的网络管理。NAT和主机模式网络取得较好的性能但安全性较差。Routing网络性能也不错但需要额外的支持。
    3. 容器网络本身就有特定的开销,由于容器网络和虚拟机的虚拟网络栈之间复杂的交互,将容器部署在虚拟机上时还会有额外的吞吐量下降和延迟增加。
    4. 容器网络有一个需要考虑的重点在于启动时间,短生命周期和延迟敏感的应用在选择一个网络时应该考虑容器网络的启动时间。

    II 单机上的容器网络

    本小节,我们会介绍4种单机容器网络模式,比较它们的不同,讨论它们的使用场景。其中一些模式是多机网络的基础。

    在这里插入图片描述
    在这里插入图片描述

    None mode

    这种容器只有一个loopback接口,不能连接到本机或其他网络上的容器。然而它可以取得很好的隔离和安全性,适合不需要网络连接的服务,如:离线数据计算,批处理,备份任务等

    桥接模式

    桥接模式的Docker容器在单机上默认网络模式。当dockerd守护进程启动时,Docker就会在宿主机的OS上创建一个名为docker0的网桥。当一个新容器启动时,会有一对vthe端口被创建出来把容器连接到docker0上。所有连接到docker0的容器属于同个虚拟子网,使用私有IP地址相互通信。单独的桥接模式不能把容器连接到外部网络,必须依赖其他服务,如NAT和overlay。桥接模式允许每个容器都拥有一个隔离网络命名空间和IP地址,所有容器间的通信需要经过docker0网桥。同个宿主机上的包传播也需要调用隔离网络命名空间路径来发送和接收,导致了很多的网络开销。另外,把容器放在独立的网络空间让安全性稍微下降了一点。

    容器模式

    如图2所示,容器模式涉及到多个容器,它们共享同一个网络命名空间。在一组里,一个容器被指定为代理配置成桥接模式,其他组内的容器通过通过代理的vthe接口连接到外网。因此所有组内的容器共享同一个网络,整个组只指定了一个IP地址,组内的单个容器通过组IP加上一个端口号来辨认。容器模式被广泛地采用在许多容器管理框架上。例如,k8s上的一个Pod是一组容器,它们共享着相同的网络空间和地址。使用容器模式网络的容器可以使用标准的进程间通信(IPC)来相互通信。容器模式比桥接模式花费更少的通信开销并取得中等水平的安全。虽然不同组的容器是隔离的,但同组的容器之间没有任何安全隔离。因此,容器模式最适合属于同个用户的容器。然而,相比起桥接模式,它没有为每个容器分配一个IP地址。但一个大规模伸缩容器部署跨多台主机时,用户就要忍受同时实现IPC和IPs混合通信的负担。

    Host模式

    运行通过宿主机上的所有容器共享宿主机OS的网络命名空间,同样的,所有容器彼此可见并且容器之间通过进程间通信。Host模式的安全级别在四种模式中最低,因为所有用户同个宿主机的IP地址和命名空间。

    总结

    表II总结了四种单机网络模式的特点。从上到下网络变得逐渐高效,但安全隔离级别逐渐下降。

    III 多机上的容器网络

    Host模式

    如第二小节讨论的,host模式下的容器共享宿主机的网络栈和命名空间。因此,不同主机上两个host模式的容器可以很容易地通信,就像两个主机上使用IP通信的两个进程一样。尽管Host模式的网络配置起来简单,但只有两个Host模式的容器能相互通信。例如,一个桥接模式的容器可以使用目的主机的IP发包给一个不同主机上的Host模式的容器,但反过来行不通。而且,Host模式对通过主机上的容器不进行安全隔离。

    NAT模式

    这个Docker 1.9之前最常用的多机容器网络技术。NAT在NAT表中映射一个容器的私有IP地址到它的端口号。通信必须使用主机的公有IP地址加上端口号来确定一个特定的容器。当容器发出一个包时,源主机把容器的私有IP重新映射成主机的公有IP地址,并改变包的头。目标主机使用接收到的包的端口号来映射到本机上容器的私有IP地址。发送端和接收端的地址转换都是在docker0这个网桥上完成的。NAT是一个实现不同主机上容器连通性的简单方法。它不需要复杂的配置和第三方软件支持。另外,因为NAT允许容器使用其宿主机的IP地址,所以在大规模容器部署中不需要大量的公有IP地址。然而,对每个发送和接收的包进行地址转换会有一些开销和性能下降。这些开销在依赖NAT的高密度容器中或者容器化的应用对性能敏感的情况下可能需要重视一下。另外一个限制是NAT模式下,容器的公有IP地址和它们的宿主机的IP绑定,导致很难实现动态网络。在一个短生命周期的容器的动态网络中,使用NAT模式避免端口冲突仍然是一个挑战。

    Overlay网络

    一个overlay网络运行在另外一个网络之上来建立节点之间定制化的连接。常用的overlay网络模式包括IPIP、vxlan、vpn等等。docker容器有很多overlay网络,虽然它们的实现各异,但核心思想都是类似的。容器在KV(key-value)存储中保存了它们私有地址和宿主机IP的映射,KV存储可以被所有主机访问到。容器使用虚拟子网中的一个私有IP地址相互通信。overlay在宿主机的网络栈中插入了额外的一层。当容器发一个包时,overlay层在KV存储中使用目标容器的私有IP地址来寻找目标主机的公有地址,然后创建一个新的包,使用目的主机的IP作为目的地址,使用原始包作为新包的装载。这个过程称为封包。一旦封装好的包到达目标主机,主机的网络栈会解开这个包得到原始包,把这个包传递给目标容器的私有IP地址。比起NAT,overlay网络提供了隔离的地址空间,并允许容器使用私有的地址进行通信。它更容易管理并能够更有弹性地修改网络的拓扑。但是overlay有两个缺点,一是封包和解包是耗时的操作,并延长了网络栈;而是封包时改变了原始包的大小,当底层网络限制了最大传输单元(MTU),封包时空间的开销可能会导致要发送的包的数量增加,因为新的包超过了MTU的限制。Docker在1.9以后有原生的overlay网络可以用,并且是多机网络默认的解决方案。

    Docker原生overlay网络

    如表III所示,Docker的overlay网络采用了vxlan桥来连接同个主机上的容器。overlay网络是构建在libkv和libnetwork之上的,使用vxlan来实现主机间容器的连通性。overlay网络是Docker swarm的默认网络,并且Docker提供了扩展API用来支持对overlay进行配置。在Docker提供overlay原生支持前,很多第三方解决方案已经提出来,这里我们讨论一下最常用的解决方案。

    在这里插入图片描述

    Weave

    Weave是由Weavework开发的私有网络解决方案。Weave在每个Docker主机上部署weave路由器容器,weave网络由这些路由器组成。weave路由器之间的通信可以使用NaCI加密库加密来增强数据安全。Weave在每个主机上创建一个vethwe-bridge网桥,来连接容器和路由器。在发送端,当一个容器发送一个包时,该主机上的Weave路由器会使用pcap的混杂模式把这个包拦截下来,转发到远程主机的weave路由器上。在接收端,weave路由器也使用pcap来把包转交给网桥,然后把包转发给目标容器。weave路由器作为一个用户层的服务,处理包的封装和解封。同样的,使用weave构建一个overlay的开销包括了把包在用户态和内核态之间拷贝的开销。

    Flannel

    Flannel由CoreOS开发的一种虚拟网络。在Docker原生的overlay中,宿主机上的Docker守护进程独立地给容器分配私有虚拟IP地址。但不同主机上的多个容器被放到同一个overlay网络时,就可能发生IP地址冲突。因此,Docker原生overlay网络需要先创建好,然后再把容器加入到这个overlay网络中来避免IP冲突。这种方式的一个主要缺点是,无法给已经运行的容器动态地创建overlay,因为没有办法处理潜在的IP冲突。Flannel通过确保所有在不同主机上的容器拥有不同的IP地址来解决这个问题。为了做到这一点,flannel限制了所有在同台主机上的容器只能使用通过子网,并且为不同主机分配不同的子网,因此可以动态地配置overlay网络而不会有IP冲突问题。Flannel维护了一个分布式的KV存储,etcd来存储overlay的信息和它们的地址映射。它会在docker0和物理设备之间插入一个虚拟网络接口flannel0。包的封装和解封在flannel0中进行。Flannel支持通过TLS来加密通信。

    Calico

    Calico是由Tigera开发的可扩展和高效的虚拟网络。它为跨主机的容器连接提供了两个选项:IPIP overlay和边界路由协议(Border Gateway Protocol ,BGP) routing。后面一种会在后面的routing网络中讨论。不像前面提到的那些使用UDP或VXLAN来封装包的overlay网络,IPIP在网络(IP)层进行包的封装。原始的IP包会在一条网络隧道(如tunl0)的源端被包含在另一个IP包中,在隧道的目的端被解封。Calico也有昂贵的封装和解封包的开销,并且还强加一个额外的限制,它需要底层的基础设施支持IPIP协议。然而,许多云厂商,并没有支持IPIP协议,如微软的Azure。

    Routing网络

    overlay网络通过在另外一个网络(underlay)之上创建一个虚拟的网络层,为容器之间提供了逻辑的网络连接。除了开销很大,overlay网络还让网络包的监控非常困难,因为真正的网络包被封装起来了。为了解决这个问题,Calico为跨主机通信提供了一种可选的方式。它在主机的内核中实现了一个虚拟路由器,使用BGP来进行包的路由。作为一个网络层的解决方案,Calico相比起NAT和overlay网络来开销没有那么大。但它也有一些限制,首先,Calico只支持部分网络协议,如TCP,UDP,ICMP,适用性有限;其次,数据中心网络还没有广泛地支持BGP网络,例如,在公有云上,BGP不能跨越zone的边界;再次,路由表的大小限制了一个容器网络的规模;最后,在短生命周期的容器组成的动态网络中,更新BGP中的路由信息也是开销很大的。Calico支持TLS来加密etcd集群和Calico组件之间的通信。

    总结

    表IV总结了可用的多机容器网络。Host模式网络简单快速,但牺牲了安全和隔离。NAT简单易用,但容器的IP和主机的IP绑定在一起,端口管理复杂并且限制了网络管理的灵活性。表III总结了各种overlay网络的结构。overlay网络提供了很好的隔离和安全,但在包处理花费了大量的开销。另外,除了weave,文中讨论的overlay网络都是基于一个集群范围的KV存储来进行私有地址和公有地址的映射。这不仅变成一个单点故障,也增加了容器启动时间的延迟。Routing网络比overlay网络更高效,但只支持部分网络协议并且需要底层基础设施支持BGP。
    在这里插入图片描述

    IV 容器网络的性能

    本节展示了本文中讨论的容器网络的性能评估。首先评估使用不同协议和不同包大小的单个和多个VM。然后研究虚拟化对容器性能的影响。最后评估不同容器网络如何应对干扰、CPU计算的开销和可扩展性。如果没有特殊说明,本文使用运行在VM上的容器来模拟公有云上的容器。

    实验设置

    硬件

    2台DELL PowerEdge T430服务器,用千兆网卡连接。每台服务器有20核的Intel Xeon E5-2640 2.6GHz处理器,64G内存和2T的7200RPM SATA硬盘。Simultaneous multithreading (SMT) 被禁用掉来减少多次实验运行结果的不同。

    软件

    使用Linux内核4.9.5和Ubuntu 16.10作为宿主机和虚拟机的OS。Hypervisor使用KVM 2.6.1,Docker使用社区版1.12。虚拟机分配了默认的rtl8139网卡接口。Overlay网络软件:etcd 2.2.5, weave 1.9.3, flannel 0.5.5 and calico 2.1。

    基准

    使用了下面的基准来衡量容器网络的性能:

    • Netperf:一个网络基准工具,提供单向吞吐量和端到端的延迟测量。本文使用2.7.0版本。
    • Sockperf:为测试高性能系统的性能(吞吐量和延迟)而设计的网络基准工具,使用socket api。本文使用2.8版本。
    • Sparkyfish:开源的网络带宽和延迟测试工具。使用TCP流来测试批量下载和上传的性能。版本1.2。
    • OSU benchmarks:一个测量消息传递接口(Message Passing Interface ,MPI)应用的工具。版本5.3.2。

    实验结果

    单个虚拟机上的容器

    首先我们比较了单个虚拟机上点对点的网络性能。虚拟机的配置是4核4G。作为对比的参考基线(baseline,为了便于理解,下文有些地方也翻译成对照组),我们在同个虚拟机上分别运行客户端和服务器进程(记为:w/o container)。图3(a)显示了使用Sparkyfish测量的批量上传和下载带宽的性能。除了桥接模式外,所有容器网络都取得了接近参考基线的性能。相比起来,桥接模式的上传和下载分别有18%和30%的性能损失。图3(b)显示了不同模式下TCP和UDP的吞吐量,使用Sockperf进行测量。包的大小设置为1024字节。类似的,桥接模式花费了更多的开销,而其它模式的开销不大。然后,我们使用osu_bw和osu_latency来测试在不同包大小的情况下网络的吞吐量和延迟。同样的,容器模式和Host模式在所有包大小中都取得了接近参考基线的性能,而桥接模式造成了10倍的吞吐量下降和延迟增加。
    一个共性是,参考基线、容器模式和Host模式的容器都共享同个网络命名空间。参考基线和Host模式共享主机OS的网络栈,而容器网络模式的容器共享的是代理容器的命名空间。同样的,这些模式中容器间的通信是在loopback接口中进行的,实际上是通过IPC实现的。相比之下,容器模式拥有独立的网络命名空间,所有通信都需要经过网桥docker0,网络栈中增加了额外的一层引入了两个开销。一是它延长了网络包处理的路径,网络包需要通过docker0传播,导致了发送端和接收端遍历了网络栈,同时在接收端引起了额外的软中断。二是它消耗了更多的CPU资源,当CPU成为瓶颈时可能导致排队延迟。

    在这里插入图片描述

    多个虚拟机上的容器

    为了评估跨主机容器网络的性能,我们使用了两台运行在同个物理机上的虚拟机,比起千兆以太网卡,这让虚拟机之间有更快速的网络连接。每台虚拟机的配置是4核4G。使用Sockperf作为测量功能,网络包的大小在TCP吞吐量测试中设置为256字节,在网络延迟测试中设置为16字节。如图4所示,和参考基线(w/o container)比起来,Host模式取得了接近参考基线的吞吐量和延迟。NAT和Calico有较大的性能损失,这是由地址转换和网络包路由的开销导致的。而所有的overlay网络都有非常大的性能损失。例如,Docker原生overlay模式有82.8%的吞吐量下降和55%的延迟增加。总的来说,网络包的封装和解封比起地址转换和路由来说开销更大。如前面讨论的,桥接模式引入了额外的网络处理,而所有的overlay都需要容器连接到网桥上,并且网络包的处理需要反复遍历网络栈。例如,在宿主机OS在传输层(4层)处理一个overlay网络包并且发现它是一个封装过的网络包的时候,就需要启动包的解封过程。解封完的网络包会被丢到以太网接口上,从接收中断处理程序处重新开始网络包的处理。然后,当网络包通过网桥传给容器时,又得重新走一遍协议栈。
    在这里插入图片描述

    网络包大小

    网络包的大小在网络性能方面有至关重要的影响。假定数据发送的速率不变,大的网络包需要传输的网络包数量更少;假定固定的发包速率,大的网络包会导致更高的数据发送速率。我们使用Sockperf来衡量同个宿主机上两个虚拟机的TCP和UDP的吞吐量。Sockperf在发送端利用开环流量控制(open loop control flow)发送固定数量的网络包。因此,增加网络包的大小可以增加数据发送的速率。图5图6显示,参考基线和Host模式在TCP和UDP下数据速率都有较大的提高。而NAT和Calico(BGP模式)有一些开销但总的吞吐量也有增加。相比之下,所有的overlay网络都有大量的吞吐量性能损失。在TCP模式下,overlay随着包的增大吞吐量并没有增大。在UDP模式下,overlay网络的吞吐量有所上升但有较大的性能损失。如前面讨论的,网络包的封装和解封需要更多的处理资源。我们测量了接收端虚拟机的CPU消耗,单个流TCP和UDP的测试使虚拟机上的一个CPU超载了。然而SMP虚拟机无法使用多个vCPU来并行进行网络包的处理。一个overlay网络包需要多个步骤的处理,包括包的解封、解封了的包的中断处理和docker0上包的转发。但是网络栈在一个特定的协议栈检查到overlay网络包之前并不知道计算量。这导致了VM上的包处理无法进行有效的负载均衡。另外,随着数据速率的增加,在VM层面虚拟网络IO的开销逐渐增加。因此,VM上虚拟IO和包处理的总CPU需求会超过单个CPU的能力,导致overlay网络包的排队延迟和吞吐量的下降。这也解释了UDP测试中overlay吞吐量的下降。
    在这里插入图片描述

    网络协议

    已有的研究显示,选择合适的网络协议对取得期望的服务质量(quality-of-service ,QoS)至关重要。图5和图6显示容器网络在TCP和UDP下性能有所不同。总的来说,TCP在所有网络中比UDP取得了更高的吞吐量(包括参考基线)。TCP实现了2个机制来高效地利用物理链接。首先,滑动窗口协议通过动态自适应数据的发送速率来避免网络拥塞;第二,TCP使用Nagles算法把小的网络包合并成一个大的网络包来提高链接的效率。网络包会先存储在内核的发送缓冲队列中,而不是从用户态收到一个包就马上发送出去,但缓冲队列满时才会把它们作为一个包发送出去。通常建议TCP比UDP更值得拥有因为可靠的传输和经过优化的吞吐量。然而,虚拟机上的容器网络让我们面临一个选择网络协议的新的挑战。如图5和图6所示,除了Host模式外,所有的跨主机容器网络在使用TCP时都比UDP有更高的吞吐量下降。如具有代表性的256字节的包大小,NAT和Calico (BGP)对比起参考基线TCP吞吐量分别下降了36%和39%,而overlay网络平均有82%的TCP吞吐量下降。相比之下,NAT只有24%的UDP吞吐量下降而Calico (BGP)的UDP吞吐量甚至还上升了,overlay网络的UDP吞吐量下降也小得多,平均38%。因为TCP的确认机制涉及更多操作和计算资源消耗,跨主机容器网络比起UDP会有更大的开销。

    虚拟化的影响

    容器可以部署在虚拟机或物理机上。有四种类型的容器部署:(1)同个物理机上;(2)同个物理机的不同虚拟机上;(3)不同物理机上;(4)不同物理机的不同虚拟机上。到目前为止,我们研究了(1)和(2)两种情况,而这次评估,我们使用(3)和(4)方式来部署容器网络。我们使用Sockperf来比较容器在物理机和虚拟机上的性能。结果如图7所示。对于那些没有达到带宽现在的网络包,硬件虚拟化和容器网络都会造成吞吐量下降。例如,相比起物理机上的性能,Sockperf直接在虚拟机上执行和在虚拟机上容器的overlay网络执行时,TCP吞吐量的下降分别为42%和50.3%。容器网络的托管和虚拟机上的虚拟网络栈加重了性能下降。这个现象在大的网络包中更明显。如图7所示,所有网络当使用1024字节的包并且在物理机上部署容器网络时,吞吐量下降都很小。和小包类似,虚拟机由于引入了多层网络虚拟化层,导致了大幅度的吞吐量下降,尤其在overlay网络中。
    在这里插入图片描述

    干扰(Interference)

    备注:Interference指一个容器在进行通信时,同个主机上有其他容器来和它争用资源,导致该容器的通信受到影响,通信的性能会有所下降。

    因为容器网络是容器基础设施一个至关重要的服务,研究它如何应对干扰是一件很有趣的事情。我们创建了一个受控制的环境,来评估来自同个虚拟机上其他容器的干扰。我们在4核4G的服务器上模拟了两种干扰:a)5个容器,每个执行一个循环,来评估有持续需求的任何 ;b)每个运行一个程序周期性的请求10%的CPU,来模拟容器频繁启动和终止。图8显示了干扰对Sockperf TCP吞吐量的影响。和没有干扰相比,所有情况在有干扰时的TCP吞吐量都下降了,包括参考基线,这是因为参考基线上的服务器进程被竞争的其他容器影响,分配到的CPU资源减少。同样的,容器网络通常包括一个用于管理网络流量的用户态的守护进程和一个用于路由和包风中的内核组件。用户态的守护进程是很容易受到干扰的,而内核受到的影响则较小,因为内核的处理相比起用户态的计算而已,是有严格的高优先级的。例如,Host模式使用宿主机的内核网络栈来处理包而Calico(BGP)在内核中实现了一个虚拟路由器,因此Host模式和Calico(BGP)都可以取得接近参考基线的性能,因为容器网络服务没有被干扰影响。与此相反,使用用户态守护进程的第三方overlay受到干扰的影响最大。这个实验告诉我们,在一个高度共用的环境中,将容器网络服务从其他用户任务中隔离出来或者在主机的OS内核中实现这个服务是比较明智的选择。
    在这里插入图片描述

    CPU负载

    为了评估各种网络的CPU负载,我们在两个物理机上创建了两个1核4G的虚拟机。我们使用Netperf UDP_RR来测量CPU的使用量。客户端和服务端的容器配置成相同的网络模式。表V显示了CPU的使用量和各种多机网络的服务需求(demand)花费的时间。由于Netperf不能测量NAT的事务率(transaction rate),所有下表中没有包含NAT的结果。CPU的使用量包括用户态、内核态和等待IO花费的时间,用百分比来测量。服务需求是完成一次UDP_RR事务的时钟时间(wall-clock time)。在所有网络中,Host模式消耗的CPU和w/o container差不多,Calico (BGP)的CPU开销更多一点,因为它的虚拟路由器会有一些额外的计算。所有overlay网络的CPU开销由于包的封装和解封则要多得多。服务需求显示了容器网络在请求层面的花费,和CPU花费的趋势类似,CPU花费越多的网络,完成一个事务的时间就更长。
    在这里插入图片描述

    可扩展性

    许多应用都是由多个组件组成,是理想的容器化使用场景。例如,web服务通常包括内存缓存,负载均衡和后端的数据库。大数据框架,如YARN,启动大量容器来并行计算一个任务。因此,探索多个容器之间并行通信的性能是非常有意义的。在MapReduce的shuffle阶段的多对多(all-to-all)通信就是一个很好的例子。我们使用OSU工具上的osu_alltoall程序来测试当容器网络动态伸缩时多对多通信的延迟。包大小设置为1024字节,使用2台配置为8核4G的虚拟机。图9(a)显示了单机容器网络的可扩展性。我们仅测试桥接模式,因为它是默认的配置并且是多机容器网络的基础。参考基线直接在VM上运行MPI程序,而w/ contailer在单独的容器中运行MPI程序。如图9(a)所示,桥接网络的延迟在容器数量增加时急剧地增加了。相比之下,参考基线在进程数量增加时能很好地扩展。很明显,当多个容器连接到docker0网桥时,该网桥会成为瓶颈。
    图9(b)和9©显示了多机(multiple VMs)容器网桥的延迟。我们评估了分布在两个VM上的两个容器。在图9(b)中,我们固定了一个容器或一个进程在一个VM上,然后把其他容器或进程都放在另外一台VM上,在图9©中,我们把容器或进程平均分到两个VM上(不能被2整除时取近似的整数值),同个VM上的容器使用桥接模式通信,不同VM上的容器使用Docker的原生overlay网络通信。如图9所示,我们有几个发现。首先,跨VM多对多通信的延迟是单个VM的10倍,意味着跨VM是延迟增加的主要原因。容器网络中的延迟要高于w/o contailer(意味着跑在VM上也会增加一些延迟)。图9©表明,当VM通信越多地通过overlay时,w/ container 和 w/o container的性能差距就越大。这意味了在弹性伸缩时,跨VM的overlay是主要的瓶颈。本次实验提供了一个容器放置的建议,在overlay网络中,应该尽量把相互通信的容器放在同个主机上来避免高昂的通信开销。
    在这里插入图片描述

    网络启动时间

    建立容器网络的时间对于短生命周期或延迟敏感的任务来说是至关重要的。我们使用none模式的容器的启动时间作为参考基线,表VI列出了配置了不同网络的容器的启动时间。这里的启动时间是指创建容器命令发出和容器回应一个ping之间的时间,结果使用了10次运行结果的平均值。在单机上,除了容器模式外,所有的网络的启动延迟都能够接近一个docke镜像的启动时间。容器模式的启动时间甚至比参考基线还更快,这是因为代理容器已经初始化好一个网络命名空间,把一个额外容器连接到代理上要比重新启动一个新的容器要快。
    在多机网络中,Host模式和NAT模式网络的启动时间和单机上的差不多。但是,启动一个overlay或者初始化BGP路由表的时间要比对照组长4.5到23倍。例如,启动一个Docker overlay需要超过10秒,大多数的时间是在注册容器到KV存储中。Calico (BGP)启动也很慢,因为它需要花几秒钟用来传播路由表。用户应该在选择合适的网络时好好考虑不同网络的延迟,从而满足应用的延迟要求。
    在这里插入图片描述

    V 相关工作

    容器网络标准

    随着容器在许多领域被采用以及容器化应用的规模持续增长,我们需要一个标准的容器网络规范。目前,容器网络接口有两种标准。容器网络模型(Container Network Model ,CNM)是Docker官方提出的标准,它包括了许多模块,如沙盒、网络和endpoints。CNM以及被VMWare和Weave等采用。容器接口模型(Container Network Interface ,CNI)是谷歌和CoreOS为通用容器网络提出的社区标准。和CNM不同的是,CNI的设计用起来更简洁和灵活。CNI以及被Apache Mesos, Kubernetes等支持。许多开源项目,如Calico,同时支持两种标准。

    容器网络优化

    随着容器的流行,越来越多的研究开始关注解决容器网络效率低的问题。Hu等人描述了容器中典型NFV任务的特征并且观察到共享主机OS的网络栈是主要的瓶颈。他们提出了NetContainer,一个为容器化的NFV平台实现了细粒度硬件资源管理的软件框架。为了解决容器性能低下的问题,Yu等人提出了FreeFlow,使用共享内存和RDMA来实现容器间高吞吐量和低网络延迟。工业界还有很多探索,例如把Docker和SR-IOV或DPDK整合起来,从而加速容器网络。这些工作和我们是正交的。

    VI 观点(insight)和结论

    观点

    为一个任务选择一个合适的网络是很有挑战性的,需要考虑许多因素。如果用户在单机上运行容器,他们需要在性能、安全和隔离之间权衡。如果安全和隔离是最重要的,桥接模式是最好的选择。如果容器需要频繁和其他容器相互通信,并且一些容器需要访问其他容器的命名空间来监控和管理,容器模式应该是最好的选择。Host模式有解决原生的性能,虽然没有提供任何隔离。如果用户在多个主机上构建容器网络,从性能考虑Calico (BGP) 是最好的选择,NAT是第二选择,如果架构不支持BGP。所有的overlay网络性能类似,引入了较大的开销。overlay网络对于不需要高性能网络但会频繁改变拓扑的任务来说是最好的选择。
    除了容器的性能,在选择合适的网络时任务的特征也是至关重要的。例如,对于使用小包进行通信的任务(如消息服务)而言,所有的多机解决方案的性能类似;对于大流量的任务,Calico (BGP)性能更好。另外,TCP任务比UDP的开销要大得多。虚拟化也带来了额外的开销,特别是对于overlay网络而言。
    为了提升容器网络的性能, 需要解决不同容器网络的瓶颈。宿主机OS上共享的网络栈、集中式的网桥docker0、Weave和Calico中的软件路由、overlay网络中包的封装和解封都有可能成为一个特定任务的瓶颈。为了提高单机上的容器网络性能,通信可以通过共享内存实现以及避免包在用户态和内核态之间拷贝。为了提高多机容器网络的性能,开销高贵的网络包封装和解封操作可以通过硬件来加速。如第IV节讨论的,有许多的因素影响着网络的性能,选择正确的网络是一件很有挑战性的事。机器学习之类的技术可以用于容器网络的自动选择。

    结论

    在本文中,我们展示了一份关于单机和多机容器网络的详细分析。我们对虚拟化环境中的各种容器网络做了一次全面的实践研究。据我们所知,本文是目前为止第一次对容器网络的多方面进行探索。我们有一些发现可以帮助用户为他们的任务选择合适的网络,以及指导已有容器网络的优化方向。

    展开全文
  • 在云计算领域随着以Docker为代表的容器引擎与...通过对容器网络插件的部署方式进行重构,将容器网络插件配置与容器集群配置之间解耦,完善了magnum容器网络的可扩展性。最后通过创建不同容器网络的集群对方案进行验证。
  • [Kubernetes]浅谈容器网络

    千次阅读 2019-03-10 18:48:07
    Veth Pair 这部分内容主要介绍一个设备: Veth ...像这样直接使用宿主机网络栈的方式,虽然可以为容器提供良好的网络性能,但也会不可避免地引入共享网络资源的问题,比如端口冲突.所以,在大多数情况下,我们都希望容器...
    Veth Pair

    这部分内容主要介绍一个设备: Veth Pair .
    作为一个容器,它可以声明直接使用宿主机的网络栈,即:不开启 Network Namespace .在这种情况下,这个容器启动后,直接监听的就是宿主机的 80 端口.
    像这样直接使用宿主机网络栈的方式,虽然可以为容器提供良好的网络性能,但也会不可避免地引入共享网络资源的问题,比如端口冲突.所以,在大多数情况下,我们都希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和端口.
    但是这个时候,就有另外一个问题了:这个被隔离的容器进程,该如何跟其他 Network Namespace 里的容器进程进行交互呢?
    最直接的办法,就是把它们用一根网线连接起来;而如果想要实现多台主机之间的通信,那就需要用网线,把它们连接在一台交换机上.
    在 Linux 中,能够起到虚拟交换机作用的网络设备,是网桥( Bridge ).它是一个工作在数据链路层( Data Link )的设备,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口( Port )上.
    为了实现这个目的, Docker 项目会默认在宿主机上创建一个名叫 docker0 的网桥,凡是连接在 docker0 网桥上的容器,都可以通过它来进行通信.
    但是,我们又该如何把这些容器"连接"到 docker0 网桥上呢?此时,我们就需要使用一种名叫 Veth Pair 的虚拟设备了.
    Veth Pair 设备的特点是:它被创建出来后,总是以两张虚拟网卡( Veth Peer )的形式成对出现的.并且,从其中一个"网卡"发出的数据包,可以直接出现在与它对应的另一张"网卡"上,哪怕这两个"网卡"在不同的 Network Namespace 里面.这样,用来连接不同 Network Namespace 的"网线"就成为了可能.

    举个例子

    比如,现在我们启动了一个叫做 nginx-1 的容器:

    $ docker run –d --name nginx-1 nginx
    

    然后我们可以进入到这个容器中,查看一下它的网络设备:

    # 在宿主机上
    $ docker exec -it nginx-1 /bin/bash
    # 在容器里
    root@2b3c181aecf1:/# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
            inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
            ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
            RX packets 364  bytes 8137175 (7.7 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 281  bytes 21161 (20.6 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
            
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10<host>
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
            
    $ route
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
    172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
    

    可以看到,在这个容器中,有一张叫做 eth0 的网卡,它正是一个 Veth Pair 设备在容器里的这一端.通过 route 命令,可以查看到 nginx-1 容器的路由表,能够看到,这个 eth0 网卡是这个容器里的默认路由设备;所有对 172.17.0.0/16 网段的请求,也会被交给 eth0 来处理(第二条 172.17.0.0 路由规则)
    而这个 Veth Pair 设备的另一端,则在宿主机上.可以通过查看宿主机的网络设备看到它,如下所示:

    # 在宿主机上
    $ ifconfig
    ...
    docker0   Link encap:Ethernet  HWaddr 02:42:d8:e4:df:c1  
              inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
              inet6 addr: fe80::42:d8ff:fee4:dfc1/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:309 errors:0 dropped:0 overruns:0 frame:0
              TX packets:372 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:0 
              RX bytes:18944 (18.9 KB)  TX bytes:8137789 (8.1 MB)
    veth9c02e56 Link encap:Ethernet  HWaddr 52:81:0b:24:3d:da  
              inet6 addr: fe80::5081:bff:fe24:3dda/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:288 errors:0 dropped:0 overruns:0 frame:0
              TX packets:371 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:0 
              RX bytes:21608 (21.6 KB)  TX bytes:8137719 (8.1 MB)
              
    $ brctl show
    bridge name bridge id  STP enabled interfaces
    docker0  8000.0242d8e4dfc1 no  veth9c02e56
    

    通过 ifconfig 命令的输出,我们可以看到, nginx-1 容器对应的 Veth Pair 设备,在宿主机上是一张虚拟网卡,它的名字是: veth9c02e56 .并且,通过 brctl show 的输出,可以看到这张网卡被"插"在了 docker0 上.
    如果此时,我们在这台宿主机上启动另一个 Docker 容器,比如 nginx-2 :

    $ docker run –d --name nginx-2 nginx
    $ brctl show
    bridge name bridge id  STP enabled interfaces
    docker0  8000.0242d8e4dfc1 no  veth9c02e56
           vethb4963f3
    

    会发现,有一个新的,名叫 vethb4963f3 的虚拟网卡,也被"插"在了 docker0 网桥上.此时,如果在 nginx-1 容器中 ping 一下 nginx-2 容器的 IP 地址( 172.17.0.3 ),就会发现,在同一宿主机上的两个容器,默认就是相互连通的.
    以上整个流程,来一张示意图:(这样可以更清楚一些)
    在这里插入图片描述
    此时,应该就可以理解了,在默认情况下,被限制在 Network Namespace 里的容器进程,实际上是通过 Veth Pair 设备 + 宿主机网桥的方式,实现了和其他容器的数据交换.
    所以,如果遇到容器连不通"外网"时,第一反应应该是先试试 docker0 网桥能不能 ping 通,然后查看一下跟 docker0 和 Veth Pair 设备相关的 iptables 规则是不是有异常,一般就能够找到问题的答案.
    以上介绍的是单机容器网络的实现原理和 docker0 网桥的作用.在这里的关键在于,容器如果想要和外界进行通信,它发出的 IP 包就必须从它的 Network Namespace 里出来,来到宿主机上,而解决这个问题的方法就是:为容器创建一个一端在容器里充当默认网卡,另一端在宿主机上的 Veth Pair 设备.

    思维扩展

    看到这里,估计你会有另外一个疑问,那我如果想要"跨主机通信"呢?
    在 Docker 的默认配置下,一台宿主机上的 docker0 网桥,和其他宿主机上的 docker0 网桥,没有任何关联,它们互相之间就没办法连通.
    但是如果我们通过软件的方式,创建一个整个集群"公用"的网桥呢?然后把集群里所有的容器都连接到这个网桥上,是不是就可以相互通信了?
    一点儿毛病都没.
    这样,我们就可以画出如下的示意图:
    在这里插入图片描述
    通过示意图,能够看到,构建这种容器网络的核心在于:我们需要在已有的宿主机网络上,再通过软件构建出一个覆盖在已有宿主机网络之上的,可以把所有容器连通在一起的虚拟网络.这种技术就是: Overlay Network (覆盖网络).
    但是这只是理论上,落实到实际,还是有些出入的.
    后面我看时间和精力,如果可能,再写一篇关于"跨主机"通信的讲解文章(感觉有些难度,我不确定能够讲清楚,但是尽量)

    以上内容来自我学习<深入剖析Kubernetes>专栏文章之后的一些见解,有偏颇之处,还望指出.
    感谢您的阅读~

    展开全文
  • docker容器网络更改

    千次阅读 2020-08-17 12:38:45
    由于粗心大意导致在创建容器时候把网络指定错了 如何在不删除容器的情况下更改容器网络呢 更改网络 ###解除容器绑定的网络 网络名词mynetwork 容器名称 lnmp [root@lnmp tp6cms]# docker network disconnect ...

    由于粗心大意导致在创建容器时候把网络指定错了 如何在不删除容器的情况下更改容器网络呢

    更改网络

    ###解除容器绑定的网络 网络名词mynetwork 容器名称 lnmp
    [root@lnmp tp6cms]# docker network disconnect mynetwork lnmp
    ##删除原先的网络
    [root@lnmp tp6cms]# docker network rm mynetwork
    ##重新创建容器网络
    [root@lnmp tp6cms]# docker network create --subnet=192.168.222.0/24 mynetwork
    7d40e0be1fcade91f8109a54a05bf0f012584e0bbb9449bec5335db247efd0be
    ##为容器重新指定网络
    [root@lnmp tp6cms]# docker network connect mynetwork lnmp 
    ##重新启动容器
    [root@lnmp tp6cms]# docker container restart lnmp
    
    

    查看效果

    [root@lnmp tp6cms]# docker exec -it lnmp bash
    [root@cfd6a87a948e /]# ip add
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    36: eth0@if37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:c0:a8:de:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 192.168.222.2/24 brd 192.168.222.255 scope global eth0
           valid_lft forever preferred_lft forever
    [root@cfd6a87a948e /]# ping 10.87.232.171
    PING 10.87.232.171 (10.87.232.171) 56(84) bytes of data.
    64 bytes from 10.87.232.171: icmp_seq=1 ttl=61 time=0.626 ms
    64 bytes from 10.87.232.171: icmp_seq=2 ttl=61 time=0.424 ms
    ^C
    --- 10.87.232.171 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1000ms
    rtt min/avg/max/mdev = 0.424/0.525/0.626/0.101 ms
    [root@cfd6a87a948e /]# ping 10.87.230.205
    PING 10.87.230.205 (10.87.230.205) 56(84) bytes of data.
    64 bytes from 10.87.230.205: icmp_seq=1 ttl=63 time=0.580 ms
    64 bytes from 10.87.230.205: icmp_seq=2 ttl=63 time=0.265 ms
    64 bytes from 10.87.230.205: icmp_seq=3 ttl=63 time=0.224 ms
    
    
    展开全文
  • 关于docker容器网络的一些理解

    千次阅读 2018-05-23 10:48:39
    写在前边的话 突然发现好久没有更新...我想和你们一起学习下docker容器网络的知识,首先声明,以下内容大部分都是来源网络,按照我对docker网络的理解,整理的一篇文章,一起学习。docker容器网络概述1:默认网络 ...

    写在前边的话

          突然发现好久没有更新博客了,像我这种频繁发表博客的人竟然也会放慢了更新的速度,其实不是说自己不去写,不去更新,只是不愿意去将就,去发表一些让别人看了没有多大帮助的文章,作为2017年的开篇博客,我想和你们一起学习下docker容器网络的知识,首先声明,以下内容大部分都是来源网络,按照我对docker网络的理解,整理的一篇文章,一起学习。


    docker容器网络概述

    1:默认网络

          在默认情况下会看到三个网络,它们是Docker Deamon进程创建的。它们实际上分别对应了Docker过去的三种『网络模式』,可以使用docker network ls来查看

    master@ubuntu:~$ sudo docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    18d934794c74        bridge              bridge              local
    f7a7b763f013        host                host                local
    697354257ae3        none                null                local

          这 3 个网络包含在 Docker 实现中。运行一个容器时,可以使用 the –net标志指定您希望在哪个网络上运行该容器。您仍然可以使用这 3 个网络。

    • bridge 网络表示所有 Docker 安装中都存在的 docker0 网络。除非使用 docker run –net=选项另行指定,否则 Docker 守护进程默认情况下会将容器连接到此网络。在主机上使用 ifconfig命令,可以看到此网桥是主机的网络堆栈的一部分。
    • none 网络在一个特定于容器的网络堆栈上添加了一个容器。该容器缺少网络接口。
    • host 网络在主机网络堆栈上添加一个容器。您可以发现,容器中的网络配置与主机相同。

    2:自定义网络

          当然你也可以自定义网络来更好的隔离容器,Docker 提供了一些默认网络驱动程序来创建这些网络。您可以创建一个新 bridge 网络或覆盖一个网络。也可以创建一个网络插件或远程网络并写入您自己的规范中。您可以创建多个网络。可以将容器添加到多个网络。容器仅能在网络内通信,不能跨网络进行通信。一个连接到两个网络的容器可与每个网络中的成员容器进行通信。当一个容器连接到多个网络时,外部连接通过第一个(按词典顺序)非内部网络提供。

    (1):docker network 命令

    执行 sudo docker network –help

    master@ubuntu:~$ sudo docker network --help
    
    Usage:  docker network COMMAND
    
    Manage Docker networks
    
    Options:
          --help   Print usage
    
    Commands:
      connect     Connect a container to a network
      create      Create a network
      disconnect  Disconnect a container from a network
      inspect     Display detailed information on one or more networks
      ls          List networks
      rm          Remove one or more networks
    
    Run 'docker network COMMAND --help' for more information on a command.
    

    (2):创建test-network网络

    执行命令: sudo docker network create test-network 
    查看: sudo docker network ls

    master@ubuntu:~$ sudo docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    18d934794c74        bridge              bridge              local
    f7a7b763f013        host                host                local
    697354257ae3        none                null                local
    c4f6d347c8b4        test-network        bridge              local
    

    查看自己创建的网络的信息

    master@ubuntu:~$ sudo docker network inspect test-network
    [
        {
            "Name": "test-network",
            "Id": "c4f6d347c8b47471b97e1b5621dd2e90aff303bb7db632db86b0bbec6ffb91d4",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.18.0.0/16",
                        "Gateway": "172.18.0.1/16"
                    }
                ]
            },
            "Internal": false,
            "Containers": {},
            "Options": {},
            "Labels": {}
        }
    ]

    另外,还可以采用其他一些选项,比如 –subnet、–gateway和 –ip-range。

    (3):启动容器连接到test-network

    sudo docker run -itd –name=test –net=test-network lt:1.0 /bin/bash

    master@ubuntu:~$ sudo docker run -itd --name=test  --net=test-network lt:1.0 /bin/bash
    09a9d7a9c37d691e0fc0f7cfdf3c9470b77f410592f9bf624fe90bff2b17e315

    再次查看信息,可以看到挂载的容器

    master@ubuntu:~$ sudo docker network inspect test-network
    [
        {
            "Name": "test-network",
            "Id": "c4f6d347c8b47471b97e1b5621dd2e90aff303bb7db632db86b0bbec6ffb91d4",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.18.0.0/16",
                        "Gateway": "172.18.0.1/16"
                    }
                ]
            },
            "Internal": false,
            "Containers": {
                "09a9d7a9c37d691e0fc0f7cfdf3c9470b77f410592f9bf624fe90bff2b17e315": {
                    "Name": "test",
                    "EndpointID": "7d1d57418a8ebde2d5404f37e27de68be41a917979fd74f394bc5fccc2601e08",
                    "MacAddress": "02:42:ac:12:00:02",
                    "IPv4Address": "172.18.0.2/16",
                    "IPv6Address": ""
                }
            },
            "Options": {},
            "Labels": {}
        }
    ]

    当然也可以动态的将容器挂载到某个网络上

    master@ubuntu:~$ sudo docker run -itd --name=test1 lt:1.0 /bin/bash
    b2aba703c5180819542d26e7bda784774ca87b896e8df612dd1b727218dde334
    master@ubuntu:~$ sudo docker network connect test-network test1
    master@ubuntu:~$ sudo docker network inspect test-network
    [
        {
            "Name": "test-network",
            "Id": "c4f6d347c8b47471b97e1b5621dd2e90aff303bb7db632db86b0bbec6ffb91d4",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.18.0.0/16",
                        "Gateway": "172.18.0.1/16"
                    }
                ]
            },
            "Internal": false,
            "Containers": {
                "09a9d7a9c37d691e0fc0f7cfdf3c9470b77f410592f9bf624fe90bff2b17e315": {
                    "Name": "test",
                    "EndpointID": "7d1d57418a8ebde2d5404f37e27de68be41a917979fd74f394bc5fccc2601e08",
                    "MacAddress": "02:42:ac:12:00:02",
                    "IPv4Address": "172.18.0.2/16",
                    "IPv6Address": ""
                },
                "b2aba703c5180819542d26e7bda784774ca87b896e8df612dd1b727218dde334": {
                    "Name": "test1",
                    "EndpointID": "5d18b876b62312698d4ce253e33b52552c9a3b1237bed90ec565d4cbd9f5710d",
                    "MacAddress": "02:42:ac:12:00:03",
                    "IPv4Address": "172.18.0.3/16",
                    "IPv6Address": ""
                }
            },
            "Options": {},
            "Labels": {}
        }
    ]


    “石器时代”的容器网络模型

          目前对于刚起步接触docker容器的筒子们(当然也包括我),大部分使用网络的方式应该是这样的,把需要暴漏的端口做端口映射(docker run -itd -p 81:80 …),例如一个主机内有很多Apache容器,每一个Apache要往外抛80的端口,那我怎么办?我需要针对第一个容器和主机80端口做映射,第二个和主机81端口做映射,依此类推,到最后发现非常混乱,没办法管理。这样的容器网络模型对于企业来说是基本没办法被采用。

    这里写图片描述

          这是石器时代网络模型,它是Docker1.9之前的容器网络,实现方式是只针对单台主机进行IPAM管理,所有主机上的容器都会连接到主机内部的一个Linux Bridge,叫Docker0,主机的IP它默认会分配172.17网段中的一个IP,因为有Docker0,所以在一个主机上的容器可以实现互联互通。但是因为IP分配的范围是基于单主机的,所以你会发现在其他主机上,也会出现完全相同的IP地址。很明显,这两个地址肯定没办法直接通信。为了解决这个问题,在石器时代我们会用端口映射,实际上就是NAT的方法。比如说我有一个应用,它有Web和Mysql,分别在不同的主机上,Web需要去访问Mysql,我们会把这个Mysql的3306端口映射到主机上的3306这个端口,然后这个服务实际上是去访问主机IP 10.10.10.3 的3306端口,这是过去的石器时代的一个做法。

          总结一下它的典型技术特征:基于单主机的IPAM;主机之内容器通讯实际上通过一个docker0的Linux Bridge;如果服务想要暴露到外部的话需要做NAT,会导致端口争抢非常严重;当然它有一个好处,对大网IP消耗比较少。


    docker容器的单主机通信

          docker容器的单主机通信使用的是容器互联技术,即 –link,映射网络端口不是吧container彼此连接起来的唯一方法。Docker的linking系统允许你吧多个 container连接起来, 让他们彼此交互信息。Docker的linking会创建一种父子级别的关系。 父container可以看到他的子container提供的信息。 
    创建一个数据库容器:

    sudo docker run -d –name db training/postgres

    然后创建一个新的 web 容器,并将它连接到 db 容器

    sudo docker run -d -P –name web –link db:db training/webapp python app.py

    此时,db 容器和 web 容器建立互联关系。 
    –link 参数的格式为 –link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名。


    docker容器的跨主机通信

          早期大家的跨主机通信方案主要有以下几种:

    • 容器使用host模式:容器直接使用宿主机的网络,这样天生就可以支持跨主机通信。虽然可以解决跨主机通信问题,但这种方式应用场景很有限,容易出现端口冲突,也无法做到隔离网络环境,一个容器崩溃很可能引起整个宿主机的崩溃。
    • 端口绑定:通过绑定容器端口到宿主机端口,跨主机通信时,使用主机IP+端口的方式访问容器中的服务。显而易见,这种方式仅能支持网络栈的四层及以上的应用,并且容器与宿主机紧耦合,很难灵活的处理,可扩展性不佳。
    • docker外定制容器网络:在容器通过docker创建完成后,然后再通过修改容器的网络命名空间来定义容器网络。典型的就是很久以前的pipework,容器以none模式创建,pipework通过进入容器的网络命名空间为容器重新配置网络,这样容器网络可以是静态IP、vxlan网络等各种方式,非常灵活,容器启动的一段时间内会没有IP,明显无法在大规模场景下使用,只能在实验室中测试使用。
    • 第三方SDN定义容器网络:使用Open vSwitch或Flannel等第三方SDN工具,为容器构建可以跨主机通信的网络环境。这些方案一般要求各个主机上的docker0网桥的cidr不同,以避免出现IP冲突的问题,限制了容器在宿主机上的可获取IP范围。并且在容器需要对集群外提供服务时,需要比较复杂的配置,对部署实施人员的网络技能要求比较高。

          上面这些方案有各种各样的缺陷,同时也因为跨主机通信的迫切需求,docker 1.9版本时,官方提出了基于vxlan的overlay网络实现,原生支持容器的跨主机通信。同时,还支持通过libnetwork的plugin机制扩展各种第三方实现,从而以不同的方式实现跨主机通信。就目前社区比较流行的方案来说,跨主机通信的基本实现方案有以下几种:

    • 基于隧道的overlay网络:按隧道类型来说,不同的公司或者组织有不同的实现方案。docker原生的overlay网络就是基于vxlan隧道实现的。ovn则需要通过geneve或者stt隧道来实现的。flannel最新版本也开始默认基于vxlan实现overlay网络。
    • 基于包封装的overlay网络:基于UDP封装等数据包包装方式,在docker集群上实现跨主机网络。典型实现方案有weave、flannel的早期版本。
    • 基于三层实现SDN网络:基于三层协议和路由,直接在三层上实现跨主机网络,并且通过iptables实现网络的安全隔离。典型的方案为Project Calico。同时对不支持三层路由的环境,Project Calico还提供了基于IPIP封装的跨主机网络实现。

    docker容器的CNI模型和CNM模型

          目前围绕着docker的网络,目前有两种比较主流的声音,docker主导的Container network model(CNM)和社区主导的Container network interface(CNI)。

    1:CNI

    (1) 概述

          Container Networking Interface(CNI)提供了一种linux的应用容器的插件化网络解决方案。最初是由rkt Networking Proposal发展而来。也就是说,CNI本身并不完全针对docker的容器,而是提供一种普适的容器网络解决方案。因此他的模型只涉及两个概念:

          容器(container) : 容器是拥有独立linux网络命名空间的独立单元。比如rkt/docker创建出来的容器。 
          这里很关键的是容器需要拥有自己的linux网络命名空间。这也是加入网络的必要条件。

          网络(network): 网络指代了可以相互联系的一组实体。这些实体拥有各自独立唯一的ip。这些实体可以是容器,是物理机,或者其他网络设备(比如路由器)等。

    (2) 接口及实现

          CNI的接口设计的非常简洁,只有两个接口ADD/DELETE。

          以 ADD接口为例

          Add container to network

          参数主要包括:

    • Version. CNI版本号
    • Container ID. 这是一个可选的参数,提供容器的id
    • Network namespace path. 容器的命名空间的路径,比如 /proc/[pid]/ns/net。
    • Network configuration. 这是一个json的文档,具体可以参看network-configuration
    • Extra arguments. 其他参数
    • Name of the interface inside the container. 容器内的网卡名

          返回值:

    • IPs assigned to the interface. ipv4或者ipv6地址
    • DNS information. DNS相关信息

    2:CNM

          相较于CNI,CNM是docker公司力推的网络模型。其主要模型如下图:

    这里写图片描述

    Sandbox

          Sandbox包含了一个容器的网络栈。包括了管理容器的网卡,路由表以及DNS设置。一种Sandbox的实现是通过linux的网络命名空间,一个FreeBSD Jail 或者其他类似的概念。一个Sandbox可以包含多个endpoints。

    Endpoint

          一个endpoint将Sandbox连接到network上。一个endpoint的实现可以通过veth pair,Open vSwitch internal port 或者其他的方式。一个endpoint只能属于一个network,也只能属于一个sandbox。

    Network

          一个network是一组可以相互通信的endpoints组成。一个network的实现可以是linux bridge,vlan或者其他方式。一个网络中可以包含很多个endpoints。

    接口

          CNM的接口相较于CNI模型,较为复杂。其提供了remote plugin的方式,进行插件化开发。remote plugin相较与CNI的命令行,更加友好一些,是通过http请求进行的。remote plugin监听一个指定的端口,docker daemon直接通过这个端口与remote plugin进行交互。

    鉴于CNM的接口较多,这里就不一一展开解释了。这里主要介绍下在进行docker的操作中,docker daemon是如何同CNM插件繁盛交互。

    调用过程

    • Create Network

          这一系列调用发生在使用docker network create的过程中。

          /IpamDriver.RequestPool: 创建subnetpool用于分配IP 
          /IpamDriver.RequestAddress: 为gateway获取IP 
          /NetworkDriver.CreateNetwork: 创建neutron network和subnet

    • Create Container

          这一系列调用发生在使用docker run,创建一个contain的过程中。当然,也可以通过docker network connect触发。

          /IpamDriver.RequestAddress: 为容器获取IP 
          /NetworkDriver.CreateEndpoint: 创建neutron port 
          /NetworkDriver.Join: 为容器和port绑定 
          /NetworkDriver.ProgramExternalConnectivity: 
          /NetworkDriver.EndpointOperInfo

    • Delete Container

          这一系列调用发生在使用docker delete,删除一个contain的过程中。当然,也可以通过docker network disconnect触发。

          /NetworkDriver.RevokeExternalConnectivity 
          /NetworkDriver.Leave: 容器和port解绑 
          /NetworkDriver.DeleteEndpoint 
          /IpamDriver.ReleaseAddress: 删除port并释放IP

    • Delete Network

          这一系列调用发生在使用docker network delete的过程中。

          /NetworkDriver.DeleteNetwork: 删除network 
          /IpamDriver.ReleaseAddress: 释放gateway的IP 
          /IpamDriver.ReleasePool: 删除subnetpool

    3:CNI与CNM的转化

          CNI和CNM并非是完全不可调和的两个模型。二者可以进行转化。比如calico项目就是直接支持两种接口模型。

          从模型中来看,CNI中的container应与CNM的sandbox概念一致,CNI中的network与CNM中的network一致。在CNI中,CNM中的endpoint被隐含在了ADD/DELETE的操作中。CNI接口更加简洁,把更多的工作托管给了容器的管理者和网络的管理者。从这个角度来说,CNI的ADD/DELETE接口其实只是实现了docker network connect和docker network disconnect两个命令。

          kubernetes/contrib项目提供了一种从CNI向CNM转化的过程。其中原理很简单,就是直接通过shell脚本执行了docker network connect和docker network disconnect命令,来实现从CNI到CNM的转化。

    展开全文
  • Docker容器网络通过网络名称空间隔离,之后会将名称空间 封闭容器 不创建任何网络设备,只有lo作为容器内部通信使用,无法与容器之外进行通信 桥接容器 默认的网络模型为桥接 桥接的时候,创建一对虚拟网络...
  • docker容器网络配置

    千次阅读 2020-06-10 13:49:24
    docker网络 docker网络驱动主要有以下几种 ...您还可以使用覆盖网络来促进群集服务和独立容器之间或不同Docker守护程序上的两个独立容器之间的通信。这种策略消除了在这些容器之间进行操作系统级路由的需要。请参
  • Docker 学习 | 第六篇:容器网络配置

    万次阅读 2018-03-31 11:59:01
    Docker 学习 | 第六篇:容器网络配置 前言 Docker容器中可以运行网络应用,可以让外部可以访问容器。Docker提供了很多对网络的配置命令。本篇文章主要介绍Docker中的网络默认配置/网络端口映射/容器互联/DNS配置...
  • 翻译版本:v1.01(将不断优化翻译质量)本文包含以下内容Docker容器就是将应用及其所依赖运行环境的完整文件系统打成一个包:包括所需代码,运行库,系统工具,系统库等。如此来保证应用和应用的运行环境始终不变,...
  • 一、docker network命令 docker network所有子命令如下: docker network create docker network connect docker network ls docker network rm docker network disconnect... 二、创建网络 在安装Docker Engin...
  • 戳蓝字“CSDN云计算”关注我们哦!编者按:关于容器网络的解决方案业界已经有较多的讨论,笔者无意继续赘述。本文从K8S的网络实现入手,重点阐述SDN在容器网络中的应用价值...
  • 常见容器网络调试工具

    千次阅读 2021-12-28 14:01:58
    bash bind-tools busybox-extras curl iproute2 iputils jq mtr net-tools nginx openssl perl-net-telnet procps tcpdump tcptraceroute wget 部署 YAML 文件 apiVersion: apps/v1 kind: Deployment ...
  • Mesos容器网络解决方案

    千次阅读 2016-09-27 14:21:32
    今天小数为大家带来的是数人云CTO肖德时在容器大会上的演讲实录,从理论说起,将实践进行到底,让我们一起来探讨容器网络的问题以及解决 Mesos是数人云的主要的技术栈之一,并且我们很早就开始在实践Mesos应用。从...
  • Docker 容器网络结构以及自定义网桥

    千次阅读 2018-02-08 17:33:09
    Docker 容器网络结构以及自定义网桥 本教程讲述了基本的Docker容器的网络管理,一共包括下面几个部分 Docker bridge网络拓扑结构 自定义bridge网桥 Docker 网络容器拓扑图探讨(bridge网桥) 1.为什么要了解...
  • 理解Docker跨多主机容器网络

    万次阅读 2016-05-31 14:35:21
    理解Docker跨多主机容器网络 二月 15, 2016 2条评论 在Docker 1.9 出世前,跨多主机的容器通信方案大致有如下三种: 1、端口映射 将宿主机A的端口P映射到容器C的网络空间监听的端口P’上,仅提供四层及...
  • 容器网络--为docker容器添加网络接口

    千次阅读 2018-07-02 22:28:12
    一 背景 默认情况下容器启动后只有一个网络接口,一般外围为eth0,且其IP地址已经提前分配。有时候我们希望为一个容器创建多个网络接口,此时可以尝试如下的方式。二 为容器添加网络接口 1 以默认的网络方式运行...
  • 由于2016年年中调换工作的原因,对容器网络的研究中断过一段时间。随着当前项目对Kubernetes应用的深入,我感觉之前对于容器网络的粗浅理解 已经不够了,容器网络成了摆在前面的“一道坎”。继续深入理解K8s网络...
  • docker容器网络通信原理分析

    万次阅读 2016-04-27 10:00:20
    docker容器网络通信原理分析原作者 冯建建@天云软件 转载请注明概述自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求。而容器的网络通信又可以分为两大方面:单主机容器上的...
  • CNI:容器网络接口详解

    千次阅读 2017-07-20 12:45:22
    目前存在网络方案 flannel、calico、openvswitch、weave、ipvlan等,而且以后一定会有其他的网络方案,这些方案接口和使用方法都不相同,而不同的容器平台都需要网络功能,它们之间的适配如果没有统一
  • 容器网络

    千次阅读 2017-07-15 11:54:15
    Docker 安装时,默认会创建三个网络,可使用“docker network ls”查看: [code="docker"] $ docker network ls NETWORK ID NAME DRIVER 7fca4eb8c647 bridge bridge 9f904ee27bf5 ...
  • Docker 容器网络不通解决方法

    千次阅读 2018-05-28 10:59:39
    #docker 容器网络不通解决方法Error response from daemon: Cannot start container eb9d501f56bc142d9bf75ddfc7ad88383b7388ca6a5959309af2165f1fff6292: iptables failed: iptables --wait -t nat -A DOCKER -p t....
  • 1.运行一个容器,开启容器80端口映射 docker run -d -p 80 httpd 2.查看,发现物理机的80并没有开 netstat -napt | grep 80 3.查看docker ps,发现容器内部开的80端口只是映射到物理机的一个随机端口上。 ...
  • 原谅分享链接 Download Container-Networking-Docker-Kubernetes.pdf 链接:... 近日 Nginx 公司的 Michael Hausenblas 发布了一本关于 docker 和 kubernetes 中的容器网络的小册子。这份资料一...
  • Flannel+K8s容器网络通信实践

    千次阅读 2016-09-23 11:23:17
    今天很高兴可以和大家分享我们普元云平台SEM使用kubernetes时,关于pod、service网络通讯的实践与大家分享。以下为今天讲的主要内容:首先来看一下我们普元云的总体架构图SEM –Software Enviroment Mgmt 向上承接...
  • 外部访问内部四、跨主机容器网络1.跨主机同网段容器通信2.跨主机不同网段容器通信 一、Docker原生网络 docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分。docker安装后会自动创建3种网络:bridge、host...
  • 介绍如何在半小时内,通过阿里云容器ACK服务和容器网络文件系统CNFS服务搭建一个简单的弹性、高可用NGINX网站。,11 月 9 日至 11 月 23 日期间,完成部署即可获得“TOMY 多美卡合金车模一辆”。 地址:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 379,585
精华内容 151,834
关键字:

容器网络

友情链接: KGSearch.zip