在多台机器上部署 GeoMX#

要在实际的地理分散的数据中心上部署 GeoMX,我们需要使用多机模式进行集群部署。

在这个教程中,我们以三台机器为例,分别是 A,B 和 C,它们的 IP 地址分别是:

  • 主机 A IP: 10.1.1.34

  • 主机 B IP: 10.1.1.29

  • 主机 C IP: 10.1.1.33

为了使用这三台机器模拟三个数据中心之间的互联网络,我们手动将这些机器上的 Docker 容器划分为三个不同的网段:

  • 主机 A 网段:172.17.34.0/24

  • 主机 B 网段:172.17.29.0/24

  • 主机 C 网段:172.17.33.0/24

备注

我们可以使用以下配置示例来配置 Docker 子网络。

在每台宿主机上,修改 Docker 配置文件 /etc/docker/daemon.json,将 bip (Bridge IP) 设置为特定的子网。例如,对于 IP 为 10.1.1.34 的主机 A,将 bip 设置为 172.17.34.1/24。对主机 B 和 C 也应用类似的修改,如下所示:

// On host A (IP 10.1.1.34)
$ sudo vim /etc/docker/daemon.json
(vim) {
(vim)   "bip": "172.17.34.1/24"
(vim) }
$ sudo service docker restart
$ sudo service docker status

这个步骤定义了每台宿主机上 Docker 子网的 IP 范围。通过这种方式分隔网络,宿主机上的每个 Docker 容器都可以有其唯一的 IP,这有助于模拟跨广域的网络互联。

请注意,一旦您更改了此配置,您需要重新启动 Docker 服务以应用更改。您可以使用 service docker status 命令检查 Docker 服务的状态,以确保它已经成功重启。

为了让不同网段的容器之间能够相互通信,我们可以配置宿主机的路由表来协助转发容器的 IP 数据包。

route 命令用于修改 Linux 内核的 IP 路由表,它定义了如何根据数据包的目地地址转发数据包。以下是在宿主机上设置 IP 路由表的示例:

// On host A (IP 10.1.1.34)
sudo route add -net 172.17.29.0 netmask 255.255.255.0 gw 10.1.1.29
sudo route add -net 172.17.33.0 netmask 255.255.255.0 gw 10.1.1.33

// On host B (IP 10.1.1.29)
sudo route add -net 172.17.33.0 netmask 255.255.255.0 gw 10.1.1.33
sudo route add -net 172.17.34.0 netmask 255.255.255.0 gw 10.1.1.34

// On host C (IP 10.1.1.33)
sudo route add -net 172.17.29.0 netmask 255.255.255.0 gw 10.1.1.29
sudo route add -net 172.17.34.0 netmask 255.255.255.0 gw 10.1.1.34

这些命令向路由表添加路由,以便将发送到宿主机上 Docker 网络(例如,172.17.29.0,172.17.33.0 和 172.17.34.0)的数据包转发到相应的宿主机 IP(分别是 10.1.1.29,10.1.1.33 和 10.1.1.34)。于是,每个宿主机上的容器都可以与其它宿主机上的容器进行通信。

接下来,我们在主机 A,B 和 C 上配置 iptables 以支持源网络地址转换(SNAT)。在该示例中,SNAT 是必需的,因为它允许不同网段的机器(此处为不同宿主机上的 Docker 容器)相互通信。这是通过将正在发送的数据包的源 IP 地址转换为宿主机 IP 地址来实现的。然后宿主机将数据包路由到其目的地,当数据包返回时,它将目的地 IP 转换回原始的 Docker 容器的 IP。

以下是如何在每台宿主机上使用 iptables 设置 SNAT 的方法:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -t nat -F POSTROUTING

// On host A (IP 10.1.1.34)
sudo iptables -t nat -A POSTROUTING -s 172.17.34.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

// On host B (IP 10.1.1.29)
sudo iptables -t nat -A POSTROUTING -s 172.17.29.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

// On host C (IP 10.1.1.33)
sudo iptables -t nat -A POSTROUTING -s 172.17.33.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

在上述指令中,iptables -t nat -A POSTROUTING -s 指令应用于来自每个 Docker 网络(-s 172.17.34.0/24-s 172.17.29.0/24-s 172.17.33.0/24)且未指向其本地网络(! -d 172.17.0.0/16)的所有数据包。-j MASQUERADE 选项则将 Docker 网络隐藏在宿主机 IP 地址之后。

通过使用 iptables 设置 SNAT,我们实现了跨不同网段的 Docker 容器之间的无缝通信,这对于像 GeoMX 这样的广域分布式系统至关重要。

备注

除了上述手动配置网络路由表的方法以外,还有许多其它方法也可以建立不同网段中 Docker 容器之间的网络互联。例如,WeaveKlonet 就是两个不错的选择。

Weave 创建了一个虚拟网络,它可以连接部署在多个宿主机上的 Docker 容器。Weave 在宿主机之间建立了一个网桥,使得容器能够像在同一个网段中一样进行通信。

以下是一个基本的示例,展示了如何使用 Weave 来连接不同宿主机上的 Docker 容器。

  1. 在每台宿主机上安装 Weave:

sudo curl -L https://raw.githubusercontent.com/weaveworks/weave/master/weave -o /usr/local/bin/weave
sudo chmod a+x /usr/local/bin/weave
  1. 在每台宿主机上启动 Weave:

weave launch
  1. 如果您有正在运行的 Docker 容器,您可以将它们连接到 Weave 网络:

weave attach <container_id>

这将把指定的容器连接到 Weave 网络。现在,所有通过 Weave 连接的容器之间都可以无缝通信,无论它们位于哪个宿主机上。如果在使用 Weave 时遇到任何问题,请参考最新的 Weave 文档以获取最新的指南。

虽然 Weave 是一个优秀的工具,但它最适用于小中型网络。对于更大的网络或者有特定性能需求的网络,Klonet 平台可能更为合适。

警告

如果宿主机之间存在防火墙,您必须允许流量通过 TCP 6783 和 UDP 6783 / 6784,它们是 Weave 的控制和数据端口。

在设置好网络并确保 Docker 容器可以彼此通信之后,下一步是在这些容器中运行 GeoMX 的进程。为了做到这一点,您需要配置 GeoMX 的环境变量(请参考 以伪分布式模式部署 GeoMX),并在不同的容器中启动对应的节点进程。

警告

请注意正确分配全局调度器和所有本地调度器的 IP 地址和端口号,应当用它们所在容器的实际 IP 地址作为这些调度器的 IP 和端口号

警告

请确保所有容器都将其端口暴露给宿主机。这个步骤叫作“端口映射”,对于允许外部应用与容器内 GeoMX 服务之间的通信至关重要。

要将容器的端口暴露到宿主机,请在运行 Docker 镜像时使用 -p 选项。例如,假如全局调度器在端口 9092 上监听,我们可以通过以下命令将其映射到其宿主机的 9092 端口上:

sudo docker run -it --rm --name geomx-cpu -p 9092:9092 lizonghango00o1/geomx:cpu-only bash

请记得调整端口号以避免容器之间端口冲突。当您将容器的端口映射到宿主机的端口时,宿主机上的这个端口就被容器预留。这意味着,在预留期间,宿主机上的其他进程或容器都不能使用这个预留端口。如果同一宿主机上的多个容器试图映射到同一个宿主机端口,就会发生端口冲突,并导致部署失败。

在设置全局参数服务器和域内参数服务器时,您需要指定全局调度器的 IP 和端口号。这通过设置环境变量 DMLC_PS_GLOBAL_ROOT_URIDMLC_PS_GLOBAL_ROOT_PORT 来完成。

对于所有的域内参数服务器和工作节点(包括全局参数服务器和主控工作节点),都需要指定他们所在机构的本地调度器的 IP 和端口号。这通过设置环境变量 DMLC_PS_ROOT_URIDMLC_PS_ROOT_PORT 来完成。

以下是一个在全局参数服务器节点中设置这些变量的例子:

DMLC_ROLE_GLOBAL=global_server \
DMLC_PS_GLOBAL_ROOT_URI=172.17.34.2 \  # IP of the global scheduler
DMLC_PS_GLOBAL_ROOT_PORT=9092 \        # Port of the global scheduler
DMLC_NUM_GLOBAL_SERVER=1 \
DMLC_NUM_GLOBAL_WORKER=2 \
DMLC_ROLE=server \
DMLC_PS_ROOT_URI=172.17.34.3 \         # IP of the local scheduler (in the central party)
DMLC_PS_ROOT_PORT=9093 \               # Port of the local scheduler (in the central party)
DMLC_NUM_SERVER=1 \
DMLC_NUM_WORKER=1 \
DMLC_ENABLE_CENTRAL_WORKER=0 \
DMLC_NUM_ALL_WORKER=4 \
PS_VERBOSE=1 \
DMLC_INTERFACE=ethwe \                 # Name of network interface, the default is ethwe if Weave is used
nohup python -c "import mxnet" > /dev/null &

请根据您实际的网络配置替换上述 IP 地址和端口号。其他环境变量的配置与之前讨论的一致。