11.2.1 基础理论
在顶层设计中,Docker网络架构由3个主要部分构成:CNM、Libnetwork和驱动。
CNM是设计标准。在CNM中,规定了Docker网络架构的基础组成要素。
Libnetwork是CNM的具体实现,并且被Docker采用。Libnetwork通过Go语言编写,并实现了CNM中列举的核心组件。
驱动通过实现特定网络拓扑的方式来拓展该模型的能力。
图11.1展示了顶层设计中的每个部分是如何组装在一起的。
接下来具体介绍每部分的细节。
1.CNM
一切都始于设计!
Docker网络架构的设计规范是CNM。CNM中规定了Docker网络的基础组成要素,完整内容见GitHub的docker/libnetwork库。
推荐通篇阅读该规范,不过其实抽象来讲,CNM定义了3个基本要素:沙盒(Sandbox)、终端(Endpoint)和网络(Network)。
沙盒 是一个独立的网络栈。其中包括以太网接口、端口、路由表以及DNS配置。
终端 就是虚拟网络接口。就像普通网络接口一样,终端主要职责是负责创建连接。在CNM中,终端负责将沙盒连接到网络。
网络 是802.1d网桥(类似大家熟知的交换机)的软件实现。因此,网络就是需要交互的终端的集合,并且终端之间相互独立。
图11.2展示了3个组件是如何连接的。
Docker环境中最小的调度单位就是容器,而CNM也恰如其名,负责为容器提供网络功能。图11.3展示了CNM组件是如何与容器进行关联的——沙盒被放置在容器内部,为容器提供网络连接。
容器A只有一个接口(终端)并连接到了网络A。容器B有两个接口(终端)并且分别接入了网络A和网络B。容器A与B之间是可以相互通信的,因为都接入了网络A。但是,如果没有三层路由器的支持,容器B的两个终端之间是不能进行通信的。
需要重点理解的是,终端与常见的网络适配器类似,这意味着终端只能接入某一个网络。因此,如果容器需要接入到多个网络,就需要多个终端。
图11.4对前面的内容进行拓展,加上了Docker主机。虽然容器A和容器B运行在同一个主机上,但其网络堆栈在操作系统层面是互相独立的,这一点由沙盒机制保证。
2.Libnetwork
CNM是设计规范文档,Libnetwork是标准的实现。Libnetwork是开源的,采用Go语言编写,它跨平台(Linux以及Windows),并且被Docker所使用。
在Docker早期阶段,网络部分代码都存在于daemon当中。这简直就是噩梦——daemon变得臃肿,并且不符合UNIX工具模块化设计原则,即既能独立工作,又易于集成到其他项目。所以,Docker将该网络部分从daemon中拆分,并重构为一个叫作Libnetwork的外部类库。现在,Docker核心网络架构代码都在Libnetwork当中。
正如读者期望,Libnetwork实现了CNM中定义的全部3个组件。此外它还实现了本地服务发现(Service Discovery)、基于Ingress的容器负载均衡,以及网络控制层和管理层功能。
3.驱动
如果说Libnetwork实现了控制层和管理层功能,那么驱动就负责实现数据层。比如,网络连通性和隔离性是由驱动来处理的,驱动层实际创建网络对象也是如此,其关系如图11.5所示。
Docker封装了若干内置驱动,通常被称作原生驱动或者本地驱动。在Linux上包括 Bridge
、 Overlay
以及 Macvlan
,在Windows上包括 NAT、Overlay
、 Transport
以及 L2 Bridge
。接下来的一节中会介绍如何使用其中部分驱动。
第三方也可以编写Docker网络驱动。这些驱动叫作远程驱动,例如 Calico
、 Contiv
、 Kuryr
以及 Weave
。
每个驱动都负责其上所有网络资源的创建和管理。举例说明,一个叫作“prod-fe-cuda”的覆盖网络由 Overlay
驱动所有并管理。这意味着 Overlay
驱动会在创建、管理和删除其上网络资源的时候被调用。
为了满足复杂且不固定的环境需求,Libnetwork支持同时激活多个网络驱动。这意味着Docker环境可以支持一个庞大的异构网络。