使用覆盖网络进行联网

本系列教程涉及群体服务的网络。对于与独立容器的联网,请参阅 与独立容器的联网。如果您需要了解有关 Docker 网络的更多一般信息,请参阅概述

此页面包含以下教程。您可以在 Linux、Windows 或 Mac 上运行它们中的每一个,但对于最后一个,您需要在其他地方运行第二个 Docker 主机。

  • 使用默认覆盖网络演示了如何使用 Docker 在初始化或加入 swarm 时自动为您设置的默认覆盖网络。该网络不是生产系统的最佳选择。

  • 使用用户定义的覆盖网络展示了如何创建和使用您自己的自定义覆盖网络来连接服务。建议在生产中运行的服务使用此方法。

  • 对独立容器使用覆盖网络 展示了如何使用覆盖网络在不同 Docker 守护进程上的独立容器之间进行通信。

先决条件

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

使用默认覆盖网络

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

本教程不会讨论有关如何实现覆盖网络的特定于操作系统的详细信息,而是重点关注覆盖网络如何从服务的角度发挥作用。

先决条件

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

这些主机将被称为managerworker-1worker-2。主机 manager将同时充当管理器和工作器,这意味着它既可以运行服务任务又可以管理集群。worker-1并且worker-2仅作为工人运行,

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

演练

创建群

在此过程结束时,所有三个 Docker 主机都将加入到 swarm 中,并使用名为 的覆盖网络连接在一起ingress

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

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

    记下打印的文本,因为它包含您将用于加入worker-1worker-2加入 swarm 的令牌。将令牌存储在密码管理器中是个好主意。

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

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

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  4. 在 上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. manager列出、和 上的 Docker 网络worker-1,并worker-2注意每个网络现在都有一个名为 的覆盖网络ingress和一个名为 的桥接网络docker_gwbridgemanager此处仅显示列表:

    $ 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_gwbridge连接ingress到 Docker 主机的网络接口,以便流量可以流入和流出 swarm 管理器和工作器。如果您创建 swarm 服务并且未指定网络,它们将连接到ingress网络。建议您为每个应用程序或可协同工作的应用程序组使用单独的覆盖网络。在下一个过程中,您将创建两个覆盖网络并将服务连接到每个网络。

创建服务

  1. 在 上manager,创建一个名为 的新覆盖网络nginx-net

    $ docker network create -d overlay nginx-net
    

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

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

    笔记

    服务只能在管理器上创建。

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

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

  3. 运行docker service ls以监视服务启动的进度,这可能需要几秒钟。

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

  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,您会发现所有服务任务容器都已连接到它。

    笔记

    尽管覆盖网络会根据需要在 swarm 工作节点上自动创建,但它们不会自动删除。

  8. 清理服务和网络。从manager运行以下命令。经理会指示工作人员自动移除网络。

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

使用用户定义的覆盖网络

先决条件

本教程假设 swarm 已设置并且您是管理器。

演练

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

    $ docker network create -d overlay my-overlay
    
  2. 使用覆盖网络启动服务并将端口 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并验证服务任务是否已连接到它。my-nginxContainers

  4. 删除服务和网络。

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

对独立容器使用覆盖网络

此示例演示了 DNS 容器发现 - 具体来说,如何使用覆盖网络在不同 Docker 守护进程上的独立容器之间进行通信。步骤是:

  • 在 上host1,将节点初始化为群(管理器)。
  • 在 上host2,将节点加入集群(工作线程)。
  • 在 上host1,创建一个可连接的覆盖网络 ( test-net)。
  • 在 上host1,运行交互式 alpine容器 ( alpine1) test-net
  • 在上host2,在 上运行交互式、独立的 alpine容器 ( alpine2) test-net
  • 打开host1,从会话内alpine1ping alpine2

先决条件

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

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

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

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

演练

  1. 设置群。

    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,按照上面的说明加入群体:

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

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

  2. 在 上host1,创建一个名为 的可连接覆盖网络test-net

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

    请注意返回的网络 ID——当您从 .NET 连接到它时,您将再次看到它host2

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

    $ 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,启动一个连接到的分离 ( -d) 和交互式 ( -it) 容器 ( ) :alpine2test-net

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

    笔记

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

  6. 在 上host2,验证是否已创建(并且具有与上test-net相同的网络 ID ):test-nethost1

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ...
    uqsof8phj3ak        test-net            overlay             swarm
    
  7. 在 上host1alpine2在 的交互式终端中执行 ping 操作alpine1

    / # 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
    

    两个容器与连接两个主机的覆盖网络进行通信。如果您在未分离的host2容器上运行另一个 alpine 容器,您可以从中进行 ping 操作(这里我们添加了 用于自动容器清理的删除选项):alpine1host2

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

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

    您必须独立停止并删除每个主机上的容器,因为 Docker 守护进程独立运行,并且这些是独立的容器。您只需删除 上的网络,host1因为当您停止 alpine2上时host2test-net就会消失。

    A。 On host2、 stop 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
    

其他网络教程