DC/OS 覆盖

了解网络覆盖拓扑

DC/OS 的默认每容器 IP 解决方案需要与运行 DC/OS 的网络无关。因此,为实现每容器 IP,我们需要使用虚拟网络。覆盖技术使容器网络拓扑与底层主机网络无关。此外,覆盖技术提供了容器流量与主机流量的完全隔离,使得对容器流量的策略执行更简单。实现覆盖技术的挑战是容器发送和接收流量时封装和解封容器流量的成本。为了最小化这些封装和解封操作对容器网络吞吐量的影响,覆盖技术必须将封装/解封操作作为内核中数据包处理流水线的一部分。

为了利用覆盖技术实现 DC/OS 的每容器 IP 解决方案,因此我们需要选择 Linux 系统内核主动支持的覆盖技术。Linux 系统内核支持的最常见覆盖技术是 VxLAN。

DC/OS 的覆盖技术设计有以下假设:

  • 由于集中式 IPAM 缺乏对可用性和可靠性的保证,我们无法使用集中式 IPAM。
  • 我们需要避免第 2 层的泛滥,使网络可扩展。这意味着我们不能依赖广播 ARP 来获取容器的 MAC 地址。

在本文档中,基于上述假设/约束,我们介绍了 DC/OS 中控制平面的软件架构,其可实现基于 VxLAN 的第 3 层覆盖。

在介绍软件架构之前,我们介绍了解释覆盖技术操作方面的数据包流程,这有助于建立对软件架构中所述各种组件的直观认识。

图 1 - 代理配置

我们可以用一个示例来阐释覆盖网络的运行。图 1 显示的是两代理 DC/OS 群集。为了让 DC/OS 覆盖网络工作,我们需要分配一个足够大的子网,为覆盖网络上运行的容器分配地址。选定的地址空间不能覆盖主机网络的地址空间,以防止在设置覆盖网络时出现任何错误配置。在图 1 中,主机网络的地址空间为 10.0.0.0/8,为覆盖网络选择的地址空间为 9.0.0.0/8。

理想情况下,我们希望 IPAM 为覆盖网络上的所有容器执行地址分配。然而,很难通过全球 IPAM 来解决可靠性和一致性问题。例如,当代理宕机时,我们如何通知 IPAM? IPAM 应该提供多大的可用性来保证群集的 99% 正常运行时间(没有 IPAM 容器就无法运行)? 鉴于全球 IPAM 引发的复杂性,我们选择采用更简单的架构,将地址空间划分为较小的块,并允许代理节点拥有这些块。在图 1 中,9.0.0.0/8 的空间已被拆分为 /24 子网,每个子网都由代理负责。代理 1 分配有 9.0.1.0/24,代理 2 分配有 9.0.2.0/24。

假设 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(代理 1)上的 Mesos 容器想要与 9.0.2.128/25(代理)上的 Docker容器通信。数据包流转如下:

  • 来自 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 覆盖网络运行,有几个元数据需要预先配置到代理中,以便进行路由和切换以正常工作。在这里,我们将列出 DC/OS 覆盖网络所需的信息。

  • 在 DC/OS 中,我们需要一个 SAM(子网分配模块),该模块将通知已分配给其的子网的代理。
  • 在代理中,我们需要一个实体,该实体为 Docker 守护程序配置了子网(图 1,9.0.1.128/25 网络)中已分配给 Docker 守护程序的那部分。
  • 在代理中,我们需要一个实体,该实体将 IP 地址分配给由 MesosContainerizer 启动的容器(图 1,9.0.1.0/25 网络)。

只有解决这些挑战,才能让 DC/OS 覆盖网络运行。我们将在下一节介绍 DC/OS 覆盖网络控制平面的软件架构。控制平面将对 一节列出的元数据 进行配置和编程,以使其正常运行。

软件架构

DC/OS 覆盖网络控制平面的软件架构。

图 2 - DC/OS 覆盖网络控制平面的软件架构

图 2 描述了我们将实现的用于为 DC/OS 覆盖网络构建控制平面的软件架构。图中橙色的块是必须构建的缺失组件。下面,我们来介绍所提供的每个缺失的组件和功能。

Mesos 的 DC/OS 模块

此流程的代码可参见 DC/OS 覆盖网络的 Mesos 模块.

要配置底层 DC/OS 覆盖网络,需要一个可以为每个代理分配子网的实体。该实体还需要配置 Linux 系统网桥,以便在自己的子网中启动 Mesos 和 Docker 容器。另外,每个代理上的 VTEP 需要分配有 IP 地址和 MAC 地址,并且代理上的路由表需要配置正确的路由,以便容器通过 DC/OS 覆盖网络进行通信。

主控 Mesos 覆盖模块

主控模块将作为 Mesos 管理节点的一部分运行,具有以下职责:

  1. 它负责为每个代理分配子网。我们将更详细地描述主控模块将如何使用复制日志来定点检查此信息在故障切换至新的主控时是否恢复。
  2. 它将监听代理覆盖模块以注册和恢复为其分配的子网。代理覆盖模块还将使用此端点了解分配给其的覆盖子网(在多个虚拟网络的情况下)、分配给覆盖网络中每个 Mesos 和 Docker 网桥的子网,以及分配给其的 VTEP IP 和 MAC 地址。
  3. 它通过 HTTP 端点 overlay-master/state 来展示 DC/OS 中所有虚拟网络的状态。此端点的响应由以下 protobuf 支持:https://github.com/dcos/mesos-overlay-modules/blob/master/include/overlay/overlay.proto#L86

代理 Mesos 覆盖模块:

代理覆盖模块作为 Mesos 代理节点的一部分运行,具有以下职责:

  1. 负责向主覆盖模块注册。注册后,它将检索分配的代理子网、分配给其 Mesos 和 Docker 网桥的子网,以及 VTEP信息(VTEP 的 IP 和 MAC 地址)。
  2. 基于分配的代理子网,负责生成 隔离器用于 MesosContainerizer. 的 CNI(容器网络接口)网络配置。
  3. 负责创建 Docker 网络,以供 使用。DockerContainerizer.
  4. 揭示 HTTP 端点 overlay-agent/overlays,虚拟网络服务使用该端点检索有关该特定代理上覆盖网络的信息。

为了让 MesosContainerizerDockerContainerizer 启动给定子网上的容器,Mesos 代理节点需要学习分配给自己的子网。另外,该子网需要在 MesosContainerizer 或 开始前得到学习。

主覆盖模块将负责分配子网、VTEP IP 以及与 VTEP 关联的 MAC 地址。尽管分配新的子网和缓存此信息本身很简单,但在管理节点故障切换过程中始终维持这些信息则具有挑战性。为了使这些信息在管理节点故障切换期间保持不变,主覆盖模块将使用 Mesos 复制日志 。允许在主控故障切换完成后,主覆盖网络模块定点检查此信息并将其恢复的算法如下:

  1. 每当新的代理覆盖模块在主模块注册时,主模块将尝试向已注册的代理模块分配 VTEP 的新子网、新 VTEP IP 和新 MAC 地址。但是,它不会用分配的信息对注册请求作出响应,直到此信息被成功写入复制日志。
  2. 故障切换时,主模块会读取复制日志并重新创建子网、VTEP IP 和 VTEP MAC 地址信息,并在内存中构建此分配信息的缓存。
  3. 如果在主控故障切换期间中途收到注册请求,代理覆盖模块的注册请求将失败。在这种情况下,代理覆盖模块负责定位新的主控并尝试使用新主控上的覆盖模块进行注册。

配置 MesosContainerizer 和 DockerContainerize 以使用分配的子网

一旦 DC/OS 模块从主 DC/OS 模块检索子网信息,它将执行以下操作,以允许 MesosContainerizerDockerContainerizer 在覆盖网络上启动容器:

对于 MesosContainerizer,DC/OS 模块可在指定位置生成 CNI 配置。CNI 配置将具有网络/cni 隔离器的网桥信息和 IPAM 信息,以便在 m-<virtual network name> 网桥上配置容器。

对于 DockerContainerizer,DC/OS 模块将检索子网,然后创建 docker network,其规范名为 . 它将使用以下 Docker 命令来操作:

注意:Docker 容器化工具与 DC/OS 覆盖网络协同工作的假设是主机运行的是 Docker v1.12 或更高版本。

注意:默认覆盖 MTU 为 1420 个字节。

虚拟网络服务 (Virtual Network Service) 是在每个代理上运行的覆盖编排服务。它是一个系统,包含 DC/OS 覆盖网络的非实时组件以及其他与网络相关的 DC/OS 服务模块。在每个代理上运行的虚拟网络服务负责以下功能:

  • 与代理覆盖网络模块对话,获取分配给代理的子网、VTEP IP 和 MAC 地址。
  • 在代理上创建 VTEP。
  • 对到各个代理上的各个子网的路由进行编程。
  • 使用 VTEP IP 和 MAC 地址对 ARP 缓存进行编程。
  • 使用 Lashup(一个分布式 CRDT 存储)可靠地将代理覆盖网络信息传播到群集中的所有代理。这是虚拟网络服务执行的最重要的功能之一,因为只有拥有群集中所有代理的全部信息,虚拟网络服务才能对所有代理上的所有覆盖子网的每个代理进行路由。