使用 overlay 网络进行联网

本系列教程讲解 swarm 服务的网络。有关独立容器的网络连接,请参阅 使用独立容器进行联网。如果您需要详细了解 Docker 网络,请参阅概览

本页包含以下教程。您可以在 Linux、Windows 或 Mac 上运行它们中的每一个,但最后一个教程需要另一台正在运行的 Docker 主机。

前提条件

这些教程要求您至少拥有一个单节点 swarm,这意味着您已经在主机上启动了 Docker 并运行了 docker swarm init 命令。您也可以在多节点 swarm 上运行这些示例。

使用默认的 overlay 网络

在此示例中,您将启动一个 alpine 服务,并从单个服务容器的角度检查网络的特性。

本教程不涉及 overlay 网络如何实现的特定于操作系统的细节,而是侧重于从服务的角度来看 overlay 如何工作。

前提条件

本教程需要三台物理或虚拟 Docker 主机,它们之间都可以相互通信。本教程假设这三台主机在同一网络上运行,且没有涉及防火墙。

这些主机将被称为 managerworker-1worker-2manager 主机将兼作 manager 和 worker,这意味着它可以运行服务任务并管理 swarm。worker-1worker-2 将仅作为 worker 运行,

如果您手边没有三台主机,一个简单的解决方案是在 Amazon EC2 等云提供商上设置三台 Ubuntu 主机,所有主机都在同一网络上,并且允许该网络上的所有主机之间进行所有通信(使用 EC2 安全组等机制),然后按照 在 Ubuntu 上安装 Docker Engine - Community 的说明进行操作。

演练

创建 swarm

在此步骤结束时,所有三台 Docker 主机都将加入 swarm,并将使用名为 ingress 的 overlay 网络连接在一起。

  1. manager 主机上,初始化 swarm。如果主机只有一个网络接口,--advertise-addr 标志是可选的。

    $ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
    

    记下打印出的文本,因为它包含用于将 worker-1worker-2 加入 swarm 的令牌。建议将令牌存储在密码管理器中。

  2. worker-1 主机上,加入 swarm。如果主机只有一个网络接口,--advertise-addr 标志是可选的。

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-1> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  3. worker-2 主机上,加入 swarm。如果主机只有一个网络接口,--advertise-addr 标志是可选的。

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  4. manager 主机上,列出所有节点。此命令只能从 manager 执行。

    $ docker node ls
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    

    您也可以使用 --filter 标志按角色过滤

    $ docker node ls --filter role=manager
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    
    $ docker node ls --filter role=worker
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    
  5. managerworker-1worker-2 主机上列出 Docker 网络,注意每个主机现在都有一个名为 ingress 的 overlay 网络和一个名为 docker_gwbridge 的桥接网络。此处仅显示 manager 主机上的列表

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    495c570066be        bridge              bridge              local
    961c6cae9945        docker_gwbridge     bridge              local
    ff35ceda3643        host                host                local
    trtnl4tqnc3n        ingress             overlay             swarm
    c8357deec9cb        none                null                local
    

docker_gwbridgeingress 网络连接到 Docker 主机的网络接口,以便流量可以在 swarm manager 和 worker 之间流动。如果您创建 swarm 服务时未指定网络,它们将连接到 ingress 网络。建议为每个应用程序或协同工作的应用程序组使用单独的 overlay 网络。在下一个步骤中,您将创建两个 overlay 网络并将服务连接到其中每一个。

创建服务

  1. manager 主机上,创建一个名为 nginx-net 的新 overlay 网络

    $ docker network create -d overlay nginx-net
    

    您无需在其他节点上创建此 overlay 网络,因为当其中一个节点开始运行需要它的服务任务时,它将自动创建。

  2. manager 主机上,创建一个连接到 nginx-net 的 5 副本 Nginx 服务。该服务将把端口 80 发布到外部世界。所有服务任务容器都可以相互通信,无需打开任何端口。

    注意

    服务只能在 manager 主机上创建。

    $ docker service create \
      --name my-nginx \
      --publish target=80,published=80 \
      --replicas=5 \
      --network nginx-net \
      nginx
    

    默认的 ingress 发布模式(在您未为 --publish 标志指定模式时使用)意味着如果您浏览到 managerworker-1worker-2 主机上的端口 80,您将被连接到其中一个 5 个服务任务的端口 80,即使您浏览的节点当前没有运行任何任务。如果您想使用 host 模式发布端口,您可以将 mode=host 添加到 --publish 输出。但是,在这种情况下,您也应该使用 --mode global 而不是 --replicas=5,因为一个给定节点上的给定端口只能由一个服务任务绑定。

  3. 运行 docker service ls 命令来监控服务启动进度,这可能需要几秒钟。

  4. managerworker-1worker-2 主机上检查 nginx-net 网络。请记住,您无需在 worker-1worker-2 上手动创建它,因为 Docker 已经为您创建了。输出会很长,但请注意 ContainersPeers 部分。Containers 列出了从该主机连接到 overlay 网络的所有服务任务(或独立容器)。

  5. manager 主机上,使用 docker service inspect my-nginx 命令检查服务,并注意服务使用的端口和端点信息。

  6. 创建一个新网络 nginx-net-2,然后更新服务以使用此网络代替 nginx-net

    $ docker network create -d overlay nginx-net-2
    
    $ docker service update \
      --network-add nginx-net-2 \
      --network-rm nginx-net \
      my-nginx
    
  7. 运行 docker service ls 命令验证服务已更新且所有任务已重新部署。运行 docker network inspect nginx-net 命令验证没有容器连接到它。对 nginx-net-2 运行相同的命令,并注意所有服务任务容器都已连接到它。

    注意

    即使 overlay 网络会在 swarm worker 节点上按需自动创建,它们也不会自动移除。

  8. 清理服务和网络。从 manager 主机上,运行以下命令。manager 将指示 worker 自动移除网络。

    $ docker service rm my-nginx
    $ docker network rm nginx-net nginx-net-2
    

使用用户定义的 overlay 网络

前提条件

本教程假设 swarm 已设置好,并且您位于 manager 主机上。

演练

  1. 创建用户定义的 overlay 网络。

    $ docker network create -d overlay my-overlay
    
  2. 使用 overlay 网络启动服务,并将端口 80 发布到 Docker 主机上的端口 8080。

    $ docker service create \
      --name my-nginx \
      --network my-overlay \
      --replicas 1 \
      --publish published=8080,target=80 \
      nginx:latest
    
  3. 运行 docker network inspect my-overlay 命令并查看 Containers 部分,验证 my-nginx 服务任务已连接到它。

  4. 移除服务和网络。

    $ docker service rm my-nginx
    
    $ docker network rm my-overlay
    

为独立容器使用 overlay 网络

此示例演示了 DNS 容器发现 -- 特别是如何使用 overlay 网络在不同 Docker 守护进程上的独立容器之间进行通信。步骤如下:

  • host1 上,将节点初始化为 swarm (manager)。
  • host2 上,将节点加入 swarm (worker)。
  • host1 上,创建一个可附加的 overlay 网络 (test-net)。
  • host1 上,在 test-net 上运行一个交互式 alpine 容器 (alpine1)。
  • host2 上,在 test-net 上运行一个交互式 (-it) 且分离 (-d) 的 alpine 容器 (alpine2)。
  • host1 上,在 alpine1 的会话中,ping alpine2

前提条件

此测试需要两台可以相互通信的不同 Docker 主机。每台主机必须在两台 Docker 主机之间打开以下端口:

  • TCP 端口 2377
  • TCP 和 UDP 端口 7946
  • UDP 端口 4789

一种简单的设置方法是准备两台虚拟机(本地或在 AWS 等云提供商上),每台都安装并运行 Docker。如果您使用 AWS 或类似的云计算平台,最简单的配置是使用一个安全组,该安全组在两台主机之间以及从您客户端 IP 地址到 SSH 端口打开所有入站端口。

此示例将 swarm 中的两个节点称为 host1host2。此示例也使用 Linux 主机,但相同的命令在 Windows 上也适用。

演练

  1. 设置 swarm。

    a. 在 host1 上,初始化 swarm(如果出现提示,请使用 --advertise-addr 指定用于与 swarm 中其他主机通信的接口的 IP 地址,例如 AWS 上的私有 IP 地址)

    $ docker swarm init
    Swarm initialized: current node (vz1mm9am11qcmo979tlrlox42) is now a manager.
    
    To add a worker to this swarm, run the following command:
    
        docker swarm join --token SWMTKN-1-5g90q48weqrtqryq4kj6ow0e8xm9wmv9o6vgqc5j320ymybd5c-8ex8j0bc40s6hgvy5ui5gl4gy 172.31.47.252:2377
    
    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    

    b. 在 host2 上,按照上述说明加入 swarm

    $ docker swarm join --token <your_token> <your_ip_address>:2377
    This node joined a swarm as a worker.
    

    如果节点未能加入 swarm,docker swarm join 命令将超时。要解决此问题,请在 host2 上运行 docker swarm leave --force,验证您的网络和防火墙设置,然后再次尝试。

  2. host1 上,创建一个名为 test-net 的可附加 overlay 网络

    $ docker network create --driver=overlay --attachable test-net
    uqsof8phj3ak0rq9k86zta6ht
    

    注意返回的 NETWORK ID -- 当您从 host2 连接到它时,您会再次看到它。

  3. host1 上,启动一个连接到 test-net 的交互式 (-it) 容器 (alpine1)

    $ docker run -it --name alpine1 --network test-net alpine
    / #
    
  4. host2 上,列出可用的网络 -- 注意 test-net 尚不存在

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ec299350b504        bridge              bridge              local
    66e77d0d0e9a        docker_gwbridge     bridge              local
    9f6ae26ccb82        host                host                local
    omvdxqrda80z        ingress             overlay             swarm
    b65c952a4b2b        none                null                local
    
  5. host2 上,启动一个连接到 test-net 的分离 (-d) 且交互式 (-it) 容器 (alpine2)

    $ docker run -dit --name alpine2 --network test-net alpine
    fb635f5ece59563e7b8b99556f816d24e6949a5f6a5b1fbd92ca244db17a4342
    

    注意

    自动 DNS 容器发现仅适用于唯一的容器名称。

  6. host2 上,验证 test-net 已创建(并且与 host1 上的 test-net 具有相同的 NETWORK ID)

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ...
    uqsof8phj3ak        test-net            overlay             swarm
    
  7. host1 上,在 alpine1 的交互式终端中 ping alpine2

    / # ping -c 2 alpine2
    PING alpine2 (10.0.0.5): 56 data bytes
    64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.600 ms
    64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.555 ms
    
    --- alpine2 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 0.555/0.577/0.600 ms
    

    这两个容器通过连接两台主机的 overlay 网络进行通信。如果您在 host2 上运行另一个未分离的 alpine 容器,您可以从 host2 ping alpine1(这里我们添加 remove 选项 以自动清理容器)

    $ docker run -it --rm --name alpine3 --network test-net alpine
    / # ping -c 2 alpine1
    / # exit
  8. host1 上,关闭 alpine1 会话(这也将停止容器)

    / # exit
    
  9. 清理容器和网络

    您必须在每台主机上独立停止和移除容器,因为 Docker 守护进程独立运行且这些是独立容器。您只需要在 host1 上移除网络,因为当您在 host2 上停止 alpine2 时,test-net 就会消失。

    a. 在 host2 上,停止 alpine2,检查 test-net 是否已移除,然后移除 alpine2

    $ docker container stop alpine2
    $ docker network ls
    $ docker container rm alpine2
    

    a. 在 host1 上,移除 alpine1test-net

    $ docker container rm alpine1
    $ docker network rm test-net
    

其他网络教程

页面选项