DC/OS 覆盖
了解网络覆盖拓扑
从网络的角度来看,若要提供类似于虚拟机环境所提供的最终用户体验,重要的是为每个容器提供自己的 IP 地址和网络命名空间。为容器提供隔离的网络堆栈可以确保逻辑网络隔离以及容器之间的网络性能隔离。另外,每容器 IP 允许您使用传统的网络操作工具 (traceroute、tcpdump、wireshark) 和您所熟悉的进程,并帮助您在调试网络连接/性能问题方面提高效率。从操作的角度来看,识别容器特定流量也变得更容易,从而简化了对容器的网络性能和安全策略的实施。
DC/OS 的默认每容器 IP 解决方案需要与运行 DC/OS 的网络无关。因此,为实现每容器 IP,我们需要使用虚拟网络。覆盖技术使容器网络拓扑与底层主机网络无关。此外,覆盖技术提供了容器流量与主机流量的完全隔离,使得对容器流量的策略执行更简单。实现覆盖技术的挑战是容器发送和接收流量时封装和解封容器流量的成本。为了最小化这些封装和解封操作对容器网络吞吐量的影响,覆盖技术必须将封装/解封操作作为内核中数据包处理流水线的一部分。
为了利用覆盖技术实现 DC/OS 的每容器 IP 解决方案,因此我们需要选择 Linux 系统内核主动支持的覆盖技术。Linux 系统内核支持的最常见覆盖技术是 VxLAN。
DC/OS 的覆盖技术设计有以下假设:
- 由于集中式 IPAM 缺乏对可用性和可靠性的保证,我们无法使用集中式 IPAM。
- 我们需要避免第 2 层的泛滥,使网络可扩展。这意味着我们不能依赖广播 ARP 来获取容器的 MAC 地址。
- 解决方案需要支持统一容器化工具 (
MesosContainerizer
) 和DockerContainerizer
。在同一个覆盖网络上,我们应当能够同时运行 Docker 和 Mesos 容器,并允许它们相互通信。
MesosContainerizer
在“m-dcos”网桥上启动,Docker 容器由 DockerContainerizer
使用 Docker 守护程序在“d-dcos”网桥上启动。下面我们看一下数据包在容器到容器通信过程中的流转过程。
### 同一主机上的容器到容器通信
假设 9.0.1.0/25 上的 Mesos 容器想要与 9.0.1.128/25 上的 Docker 容器通信。数据包流转如下:
- 9.0.1.0/25 上的容器将数据包发送到默认网关,此示例中为“m-dcos”网桥,分配了 IP 地址 9.0.1.1/25。
- m-dcos 网桥将处理数据包,由于 m-dcos 网桥存在于主机网络命名空间中,因此它将向网络堆栈发送数据包以进行路由。
- 数据包将被发送到 d-dcos,它将数据包切换到 9.0.1.128/25 子网。
- 来自 9.0.1.0/25 的数据包将被发送到“m-dcos”网桥 (9.0.1.1/25) 上的默认网关。该网桥将处理数据包并将其发送到网络堆栈。由于网桥已在主机网络命名空间中,数据包将使用主机网络命名空间路由表进行路由。
- 主机路由表中存在一条路由 9.0.2.0/24 -> 44.128.0.2(将在下一节说明如何安装此路由),这实质上是告诉主机为发送此数据包,您需要通过 VxLAN1024 来发送(也存在 44.128.0.0/20 -> VxLAN1024 的路由条目)。
- 由于 44.128.0.2 直接连接在 VxLAN1024 上,内核会尝试对 44.128.0.2 进行 ARP 解析。在配置覆盖网络期间,DC/OS 会在 ARP 缓存中为 VTEP 端点 44.128.0.2 安装一个条目,因此内核 ARP 查找会成功。
- 内核路由模块会将目标 MAC 设置为70:B3:D5:00:00:02的数据包发送给 VxLAN 设备VxLAN1024。
- 要转发数据包,VxLAN1024 需要一个 MAC地址 为70:B3:D5:00:00:01作为密钥的条目。VxLAN 转发数据库中的此条目由 DC/OS 进行编程,指向代理 2 的 IP 地址。DC/OS 能够对此条目进行编程的原因是因为它知道代理的 IP 和所有代理上存在的 VTEP。
- 此时,数据包封装在 UDP 头(由 VxLAN FDB 指定)中,并被发送到存在于代理 2 的 VTEP。
- 代理 2 上的 VxLAN1024 对数据包进行解封,由于目标 MAC 地址设置为代理 2 上 VxLAN1024 的 MAC 地址,因此该数据包将由代理 2 上的 VxLAN1024 进行路由。
- 在代理 2 中,路由表具有子网 9.0.2.128/25 的条目,直接连接到网桥“d-dcos”。因此,数据包将被转发到连接至“d-dcos”网桥的容器进行处理。
- 在 DC/OS 中,我们需要一个 SAM(子网分配模块),该模块将通知子网代理节点,表示已对其进行了分配。
- 在代理中,我们需要一个实体,该实体为 Docker 守护程序配置了子网(图 1,9.0.1.128/25 网络)中已分配给 Docker 守护程序的那部分。
- 在代理中,我们需要一个实体,该实体将 IP 地址分配给由
MesosContainerizer
启动的容器(图 1,9.0.1.0/25 网络)。 - 在 DC/OS 中,我们需要一个实体,该实体将使用所有代理上存在的所有 VTEP 的 MAC 地址,以及正确封装数据包所需的解封信息(代理 IP、UDP 端口),为每个代理上的 VxLAN 转发数据库编程。该实体还需要用所有 VTEP 的 MAC 地址对每个代理上的 ARP 缓存编程,用于其对应的 IP 地址。
- 它负责为每个代理分配子网。我们将更详细地描述主控模块将如何使用复制日志来定点检查此信息在故障切换至新的主控时是否恢复。
- 它将监听代理覆盖模块以注册和恢复为其分配的子网。代理覆盖模块还将使用此端点了解分配给其的覆盖子网(在多个虚拟网络的情况下)、分配给覆盖网络中每个 Mesos 和 Docker 网桥的子网,以及分配给其的 VTEP IP 和 MAC 地址。
- 它通过 HTTP 端点
overlay-master/state
来展示 DC/OS 中所有虚拟网络的状态。此端点的响应由以下 protobuf 支持:https://github.com/dcos/mesos-overlay-modules/blob/master/include/overlay/overlay.proto#L86
- 负责向主覆盖模块注册。注册后,它将检索分配的代理子网、分配给其 Mesos 和 Docker 网桥的子网,以及 VTEP信息(VTEP 的 IP 和 MAC 地址)。
- 基于分配的代理子网,负责生成
network/cni
隔离器用于MesosContainerizer
的 CNI(容器网络接口)网络配置。 - 负责创建 Docker 网络,以供
DockerContainerizer
使用。 - 揭示 HTTP 端点
overlay-agent/overlays
,虚拟网络服务使用该端点检索有关该特定代理上覆盖网络的信息。
MesosContainerizer
和 DockerContainerizer
启动给定子网上的容器,Mesos 代理节点需要学习分配给自己的子网。另外,该子网需要在 MesosContainerizer
或 DockerContainerizer
开始前得到学习。
主覆盖模块将负责分配子网、VTEP IP 以及与 VTEP 关联的 MAC 地址。尽管分配新的子网和缓存此信息本身很简单,但在管理节点故障切换过程中始终维持这些信息则具有挑战性。为了使这些信息在管理节点故障切换期间保持不变,主覆盖模块将使用 Mesos 复制日志“Mesos 文档”。允许在主控故障切换完成后,主覆盖网络模块定点检查此信息并将其恢复的算法如下:
- 每当新的代理覆盖模块在主模块注册时,主模块将尝试向已注册的代理模块分配 VTEP 的新子网、新 VTEP IP 和新 MAC 地址。但是,它不会用分配的信息对注册请求作出响应,直到此信息被成功写入复制日志。
- 故障切换时,主模块会读取复制日志并重新创建子网、VTEP IP 和 VTEP MAC 地址信息,并在内存中构建此分配信息的缓存。
- 如果在主控故障切换期间中途收到注册请求,代理覆盖模块的注册请求将失败。在这种情况下,代理覆盖模块负责定位新的主控并尝试使用新主控上的覆盖模块进行注册。
MesosContainerizer
和 DockerContainerizer
在覆盖网络上启动容器:
对于 MesosContainerizer
,DC/OS 模块可在指定位置生成 CNI 配置。CNI 配置将具有网络/cni 隔离器的网桥信息和 IPAM 信息,以便在 m-<virtual network name>
网桥上配置容器。
对于 DockerContainerizer
,DC/OS 模块将检索子网,然后创建 docker network
,其规范名为 d-<virtual network name>
。它将使用以下 Docker 命令来操作:
注意:让
docker network create \
—driver=bridge \
—subnet=<CIDR> \
—opt=com.docker.network.bridge.name=d-<virtual network name>
—opt=com.docker.network.bridge.enable_ip_masquerade=false
—opt=com.docker.network.driver.mtu=<overlay MTU>
<virtual network name>
Docker 容器化工具
与 DC/OS 覆盖网络协同工作的假设是主机运行的是 Docker v1.12 或更高版本。
注意:默认覆盖 MTU 为 1420 个字节。
### 虚拟网络服务:覆盖网络编排
此过程的代码可以在 https://github.com/dcos/navstar.git 找到。
虚拟网络服务 (Virtual Network Service) 是在每个代理上运行的覆盖编排服务。它是一个系统,包含 DC/OS 覆盖网络的非实时组件以及其他与网络相关的 DC/OS 服务模块。在每个代理上运行的虚拟网络服务负责以下功能:
- 与代理覆盖网络模块对话,获取分配给代理的子网、VTEP IP 和 MAC 地址。
- 在代理上创建 VTEP。
- 对到各个代理上的各个子网的路由进行编程。
- 使用 VTEP IP 和 MAC 地址对 ARP 缓存进行编程。
- 使用 VTEP MAC 地址和隧道端点信息对 VxLAN FDB 进行编程。
- 使用 Lashup(一个分布式 CRDT 存储)可靠地将代理覆盖网络信息传播到群集中的所有代理。这是虚拟网络服务执行的最重要的功能之一,因为只有拥有群集中所有代理的全部信息,虚拟网络服务才能对所有代理上的所有覆盖子网的每个代理进行路由。