背景
Docker容器之间是通过namespace互相隔离的,每个容器都有自己独立的用户空间环境,那么docker是如何支持容器间或容器和宿主机间通信呢?
docker 网络设计
基于docker容器的轻量高效动态可移植等特性,docker网络在设计时也具有以下特性,该特性也方便更好的支持微服务,提供高效的连接和安全的隔离。
- 可移植性
在利用独特的网络特性的同时,还保证在各种网络环境中的最大可移植性 - 服务发现
及时发现和扩展服务,提供dns动态解析 - 负载均衡
随着服务的启动和扩展,提供服务负载均衡功能 - 安全
对网络中的容器进行隔离和访问控制 - 性能
减少延迟和最大化带宽的同时提供高级网络服务,方便更好的支持微服务 - 可扩展性
方便在多个主机之间扩展应用程序
CNM
Docker网络架构核心是建立在称为 容器网络模型(Container Network Model,简称CNM)的一组接口上,只要符合这个模型的网络接口就能被用于容器之间通信,而通信的过程和细节可以完全由网络接口来实现。
CNM的理念是在各种基础网络架构之间提供应用程序可移植性。
CNM的三个高级结构,和基础网络结构无关,在基础网络之上,方便应用程序可移植性:
Sandbox:包含容器的网络堆栈的配置。包括相应的网卡配置、路由表、DNS配置等。沙箱是伴随容器的生命周期的,可以看成是容器的网络环境;
Endpoint:Endpoint将Sandbox连接到网络,具体表现为容器中eth0,eth1这些虚拟网卡;
Network:连通两个或多个Endpoint,指的是一个能够相互通信的容器网络,提供容器互相访问的通道。 网络的实现可以是Linux网桥,VLAN等。
docker 网络驱动
CNM提供了网络驱动程序接口,Docker的网络驱动程序提供了使网络正常工作的实际实现。它们是可插拔的,因此可以轻松使用和互换不同的驱动程序,以支持不同的应用场景。
Docker支持的网络驱动较多,根据不同应用场景可分为:
docker自带驱动:
- 宿主机内部容器通信:bridge,host,container和none;
- 跨主机容器通信:macvlan,overlay;
第三方驱动:
- 大规模集群跨主机容器通信: flannel、pipework、weave 和 calico。
CNM还提供另一种驱动程序,IPAM驱动程序,区别于网络驱动程序,支持手动分配ip地址。
其他技术支撑
网络命名空间:是用于隔离容器网络资源(IP、网卡、路由等)。网络名称空间可确保同一主机上的两个容器无法相互通信,甚至不能与主机本身进行通信,除非配置为通过Docker网络进行通信。通常,CNM网络驱动程序为每个容器实现单独的名称空间。但是,容器可以共享相同的网络名称空间,甚至可以是主机的网络名称空间的一部分。
由于一个容器网络最多存放在一个网络命名空间中且互相隔离,所以通过 veth pair 在不同的网络命名空间中创建通道,负责不同网络命名空间的通信。
veth pair:用于不同network namespace间进行通信。veth是全双工链接,在每个名称空间中都有一个接口,充当两个网络名称空间之间的连接线,负责将一个 network namespace 数据发往另一个 network namespace 的 veth。
如当容器连接到Docker网络时,veth的一端放置在容器内部(通常视为ethX接口),而另一端连接到Docker网络(vethxxx)。
iptables:负责包过滤,端口映射和负载均衡。
宿主机内部容器通信
bridge
docker默认网络类型,默认网桥为docker0(172.17.0.1/16),容器间通过docker0通信。
docker bridge和linux bridge不同,后者是Linux桥接器的更高级别的实现。docker bridge本质是nat桥。
可以看到创建的容器默认会创建一个eth0虚拟网卡创建一对虚拟接口,即veth pair,分别放到宿主机和容器中;
默认bridge和自定义bridge:
自定义的网桥和默认网桥类似,但用户定义的网桥网络优于默认网桥网络:
自定义的网桥优势:优势对比
自定义bridge:
docker network create --subnet=10.10.0.0/16 --gateway=10.10.0.1 --driver bridge mybridge10 #创建自定义bridge
docker run -it --name 10_b1 --net mybridge10 busybox sh # 关联容器
docker network connect mybridge10 b1 # 将b1 加入mybridge10网络
docker network disconnect mybridge10 b1 # 断开mybridge10网络和b1的连接
创建mybridge10网络和处于mybridge10网络的10_b1容器:
可以看到宿主机新增了自定义br桥和10_b1容器对应的接口:
将b1 加入mybridge10网络:
自定义网桥会自动dns解析:
host
和宿主机共享网络,仅共享network namespace,其他namespace隔离。该容器创建时不会分配自己的IP地址,使用主机ip地址,其开通的服务端口可直接通过主机ip:端口访问。
docker run -it --name b2 --net host busybox
可以看到下面容器读取到的ip信息和tcp信息直接是宿主机的ip信息和tcp信息
宿主机ip和tcp信息
访问容器8080端口服务:
none
容器有自己的网络堆栈和网络命名空间,但不分配接口,仅存在lo接口,适合不需要通过网络通信的容器。什么情况下容器要禁用网络呢???
container
容器c1共享之前的容器b1网络,网络环境相同,仅通过端口区分服务,两容器用同一端口即会冲突。
docker run -it --name c1 --rm --net container:b1 busybox sh
容器c1:
跨主机容器通信
端口映射
-P|p指定一个docker主机端口给容器中的端口做映射,可以实现跨主机通信。不适合容器间互相通信,手动映射有点麻烦。
docker run -d --name mynginx -p 8080:80 nginx
macvlan
macvlan 本身是 linux kernel 模块,允许在同一个物理网卡上配置多个 MAC 地址,即多个 interface,每个 interface 可以配置自己的 IP。
macvlan 的最大优点是性能极好,相比其他驱动,macvlan 不需要创建 Linux bridge,而是直接通过以太接口连接到物理网络。由于么有物理机测试,so只做介绍,具体我也不了解。
overlay(swarm network)
跨节点容器网络互联,比较通用的是使用 overlay 网络。
overlay涉及到三个网络: overlay ingress bridge
其他:overlay_sbox lb_overlay
docker network create --driver overlay --ingress --subnet=10.11.0.0/16 --gateway=10.11.0.1 --opt com.docker.network.driver.mtu=1200 myingress11
docker service create --name hostname --publish target=8000,published=8080 --network myingress11 --replicas=3 xlbubble/hostname:1.0
注意:自定义overlay与默认overlay的区别:默认没有服务发现,dns解析。
集群内部通信-- flannel
这里仅介绍flannel。
flannel安装:https://blog.51cto.com/13941177/2299470
暂时先这样吧
博客参考和扩展
- 网络:https://success.docker.com/article/networking
- overlay详解:https://www.jianshu.com/p/c83a9173459f