Docker入门系列 5. Docker 容器网络的概念及网络配置 覆盖网络


1. 使用覆盖网络

覆盖网络驱动程序在多个 Docker 守护进程主机之间创建一个分布式网络。 这个网络位于(覆盖)主机特定网络的顶部,允许连接到它的容器(包括群服务容器)在启用加密时进行安全通信。 Docker 透明地处理每个数据包与正确的 Docker 守护进程主机和正确的目标容器之间的路由。。

当你初始化一个群或者将一个 Docker 主机加入到一个已经存在的群中时,会在 Docker 主机上创建两个新的网络:

  • 一个称为ingress的覆盖网络,用于处理与群体服务有关的控制和数据流。当您创建一个群服务并且不将其连接到用户定义的覆盖网络时,默认情况下它将连接到网络ingress

  • 一个名为docker_gwbridge的桥接网络,它将各个独立的Docker守护程序连接到该集群中的其他守护程序。

您可以使用 docker network create 创建用户定义的覆盖网络,就像您可以创建用户定义的桥接网络一样。 服务或容器可以同时连接到多个网络。 服务或容器只能通过它们各自连接的网络进行通信。

虽然可以将群服务和独立容器连接到覆盖网络,但默认行为和配置问题是不同的。 基于这个原因,这个主题的其余部分被分为适用于所有覆盖网络的操作,适用于群服务网络的操作,以及适用于独立容器使用的覆盖网络的操作。

2. 所有覆盖网络的操作

2.1 创建覆盖网络

先决条件:

  • 使用覆盖网络的Docker守护程序的防火墙规则

    你需要下面的端口对来往于参与覆盖网络的每个 Docker 主机的通信开放:

    • 用于集群管理通信的 TCP 端口2377
    • 用于节点间通信的 TCP 和 UDP 端口7946
    • 用于覆盖网络流量的 UDP 端口4789
  • 在创建覆盖网络之前,您需要使用 Docker swarm init 将 Docker 守护进程初始化为一个群管理器,或者使用 Docker swarm join 将其加入到现有的群中。 这两者中的任何一个都会创建默认的入口覆盖网络,该网络默认由群服务使用。 你需要这样做,即使你从来没有计划使用群服务。 然后,您可以创建其他用户定义的覆盖网络。

要创建一个覆盖网络来使用群服务,可以使用如下命令:

$ docker network create -d overlay my-overlay

要创建一个覆盖网络,它可以被群服务或独立容器用来与运行在其他 Docker 守护进程上的其他独立容器进行通信,添加--attachable标志:

$ docker network create -d overlay --attachable my-attachable-overlay

您可以指定IP地址范围,子网,网关和其他选项。

2.1 加密覆盖网络上的流量

在 GCM 模式下,所有群服务管理流量默认情况下使用 AES 算法进行加密。 群中的管理器节点每12小时轮换用于加密传播协议数据的密钥。

要加密应用程序数据,在创建覆盖网络时添加--opt encrypted。这样就可以在 vxlan 级别实现 IPSEC 加密。 这种加密会带来不可忽视的性能损失,因此在生产中使用此选项之前应该对其进行测试。

当您启用覆盖加密时,Docker 会在所有节点之间创建 IPSEC 隧道,在这些节点中,任务被安排用于连接到覆盖网络的服务。 这些隧道也使用 AES 算法在 GCM 模式,并且管理器节点每12小时自动轮换一次密钥。

不要将Windows节点附加到加密的覆盖网络。
Windows不支持覆盖网络加密。如果Windows节点尝试连接到加密的覆盖网络,则不会检测到错误,但是该节点无法通信。

群集模式覆盖网络和独立容器

您可以同时使用覆盖网络功能,--opt encrypted --attachable 并将非托管容器附加到该网络:

$ docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network

2.2 自定义默认入口网络

大多数用户从不需要配置ingress网络,但是Docker 17.05及更高版本允许您进行配置。如果自动选择的子网与网络上已经存在的子网发生冲突,或者您需要自定义其他低级别的网络设置(例如MTU),这将很有用。

自定义ingress网络涉及删除并重新创建它。这通常在集群中创建任何服务之前完成。如果您拥有发布端口的现有服务,那么在删除ingress网络之前需要删除这些服务。

在没有ingress网络的时候,不发布端口的现有服务继续运行,但是负载不平衡。 这会影响发布端口的服务,比如发布端口80的 WordPress 服务。

  1. 使用docker network inspect ingress检查ingress网络,并移除与其连接的容器的任何服务。这些是发布端口的服务,例如发布端口80的WordPress服务。如果不停止所有这些服务,下一步就会失败。

  2. 移除现有ingress网络:

    $ docker network rm ingress
    
    WARNING! Before removing the routing-mesh network, make sure all the nodes
    in your swarm run the same docker engine version. Otherwise, removal may not
    be effective and functionality of newly created ingress networks will be
    impaired.
    Are you sure you want to continue? [y/N]
  3. 使用--ingress标志创建一个新的覆盖网络,以及您想要设置的自定义选项。 此示例将 MTU 设置为1200,将子网设置为10.11.0.0/16,并将网关设置为10.11.0.2

    $ docker network create \
    --driver overlay \
    --ingress \
    --subnet=10.11.0.0/16 \
    --gateway=10.11.0.2 \
    --opt com.docker.network.driver.mtu=1200 \
    my-ingress

    注意:您可以将ingress网络命名为别的名称,但只能有一个。 试图创建第二个的尝试失败。

  4. 重新启动在第一步中停止的服务。

2.3 自定义docker_gwbridge接口

docker_gwbridge是一个虚拟网桥,它将覆盖网络(包括入口网络)连接到单个 Docker 守护进程的物理网络。 当初始化一个群或者将一个 Docker 主机加入到一个群中时,Docker 会自动创建它,但它不是 Docker 设备。 它存在于 Docker 主机的内核中。 如果您需要自定义它的设置,那么您必须在加入 Docker 主机到群体之前或者从群体中临时移除主机之后这样做。

  1. 停止 Docker。

  2. 删除现有的 docker gwbridge 接口。

    $ sudo ip link set docker_gwbridge down
    
    $ sudo ip link del dev docker_gwbridge
  3. 启动 Docker。不要连接或初始化集群服务。

  4. 使用自定义设置,使用 docker network Create 命令手动创建或重新创建 docker gwbridge。 此示例使用子网10.11.0.0 / 16。 有关可自定义选项的完整列表,请参见桥接驱动程序选项。

    $ docker network create \
    \--subnet 10.11.0.0/16 \
    \--opt com.docker.network.bridge.name=docker_gwbridge \
    \--opt com.docker.network.bridge.enable_icc=false \
    \--opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
  5. 初始化或加入群。由于桥已经存在,Docker 不会自动创建它。

3. 群服务的操作

3.1 在覆盖网络上发布端口

连接到同一覆盖网络的群服务有效地将所有端口相互暴露。 对于可以在服务之外访问的端口,必须使用 -p-- publish 标志在 docker service createdocker service update时发布该端口。 支持旧的冒号分隔语法和新的逗号分隔值语法。 较长的语法是首选的,因为它在一定程度上是自文档化的。

标志值描述
-p 8080:80 - p 8080:80 或 -p published=8080,target=80将服务上的 TCP 端口80映射到路由网格上的端口8080
-p 8080:80/udp 或 -p published=8080,target=80,protocol=udp将服务上的 UDP 端口80映射到路由网上的端口8080
-p 8080:80/tcp -p 8080:80/udp 或 -p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp将服务上的 TCP 端口80映射到路由网格上的 TCP 端口8080,将服务上的 UDP 端口80映射到路由网格上的 UDP 端口8080

3.2 绕过集群服务的路由网格

默认情况下,发布端口的群服务使用路由网格来发布端口。 当您连接到任何群节点上的发布端口时(无论它是否运行给定的服务) ,您都会被重定向到正在透明地运行该服务的工作节点。 实际上,Docker 充当了你的群服务的负载平衡器。 使用路由网格的服务以虚拟 IP (VIP)模式运行。 即使是在每个节点上运行的服务(通过 -- mode glocal标志)也使用路由网格。 当使用路由网格时,不能保证哪个 Docker 节点为客户机请求提供服务。

要绕过路由网格,可以通过将 -- endpoint-mode 标志设置为 dnsrr,使用 DNS Round Robin (DNSRR)模式启动服务。 您必须在集群服务前面运行自己的负载均衡器。 针对 Docker 主机上的服务名称的 DNS 查询将返回运行该服务的节点的 IP 地址列表。 配置您的负载平衡器来使用这个列表并平衡节点之间的流量。

3.3 分离控制和数据通信

默认情况下,与集群管理和应用程序之间的通信相关的控制通信在同一网络上运行,不过群控通信是加密的。 您可以将 Docker 配置为使用单独的网络接口来处理两种不同类型的流量。 初始化或加入群时,分别指定 ·– advertised-addr· 和 ·– datapath-addr·。 您必须为加入群的每个节点执行此操作。

4. 覆盖网络上独立容器的操作

4.1 将独立的容器连接到覆盖网络

ingress网络是在没有-- attachable标志的情况下创建的,这意味着只有群服务可以使用它,而不是单独的容器。 您可以将独立容器连接到用户定义的覆盖网络,这些覆盖网络是用 -- attachable标志创建的。 这使得运行在不同 Docker 守护进程上的独立容器能够进行通信,而无需在单个 Docker 守护进程主机上设置路由。

4.2 发布端口

标志值描述
-p 8080:80将容器中的 TCP 端口80映射到覆盖网络上的8080端口
-p 8080:80/udp在覆盖网络上将容器中的 UDP 端口80映射到8080端口
-p 8080:80/sctp将容器中的 SCTP 端口80映射到覆盖网络上的8080端口
p 8080:80/tcp -p 8080:80/udp将容器内的 TCP 端口80映射到覆盖网络上的 TCP 端口8080,将容器内的 UDP 端口80映射到覆盖网络上的 UDP 端口8080

4.3 容器发现

对于大多数情况,应该连接到服务名称,该名称是负载平衡的,由支持服务的所有容器(“任务”)处理。 若要获取支持服务的所有任务的列表,请对任务执行 DNS 查找 tasks.<service-name>

5. 实践练习 覆盖网络

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

  • 使用用户定义的覆盖网络 演示了如何创建和使用自己的自定义覆盖网络来连接服务。建议将其用于生产中运行的服务。

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

  • 容器与群集服务之间的通信 演示了使用可附加的覆盖网络,在独立容器和群服务之间建立通信。 这在 Docker 17.06及更高版本中得到了支持。

5.1 前提条件

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

最后一个示例需要Docker 17.06或更高版本。

5.2 使用默认的覆盖网络

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

前提条件

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

这些主机将被称为 manager、 worker-1和 worker-2。 管理器主机既是管理节点又是工作节点,这意味着它既可以运行服务任务,也可以管理集群。 工作节点1号和工作节点2号只起工作节点的作用,

如果你手头没有三台主机,一个简单的解决方案是在云提供商(比如 Amazon EC2)上安装三台 Ubuntu 主机,它们都在同一个网络上,允许所有主机通信(使用 EC2安全组之类的机制) ,然后按照 Ubuntu 上 Docker Engine-Community 的安装说明进行安装。

演练

创造集群

在这个过程的最后,所有三个 Docker 主机将被加入到群体中,并且将使用一个称为入口的覆盖网络连接在一起。

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

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

    记下输出的文本,因为它包含将用于将 worker-1和 worker-2加入到群体中的令牌。 将令牌存储在密码管理器中是一个好主意。

  2. 在 worker-1上,加入群体。如果主机只有一个网络接口,则 – advertised-addr 标志是可选的。

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

    $ docker swarm join --token <TOKEN> \
    --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
    <IP-ADDRESS-OF-MANAGER>:2377
  4. 在管理节点上,列出所有的节点。这个命令只能从管理器执行。

    $ 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、 worker-1和 worker-2上列出 Docker 网络,注意它们现在都有一个覆盖网络,称为ingress网络和一个桥接网络,称为 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 主机的网络接口连接起来,这样就可以在群管理节点和工作节点之间进行通信。 如果您创建了群服务,但没有指定网络,那么它们将连接到ingress网络。 建议您为每个应用程序或将一起工作的应用程序组使用单独的覆盖网络。 在下一个过程中,您将创建两个覆盖网络,并将服务连接到每个覆盖网络。

创造服务
  1. 在 manager 上,创建一个新的覆盖网络 nginx-net:

    $ docker network create -d overlay nginx-net

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

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

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

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

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

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

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

  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运行相同的命令,并注意所有服务任务容器都连接到它。

    注意: 即使覆盖网络是根据需要在群工作节点上自动创建的,它们也不会被自动删除。

  8. 清理服务和网络。 从 manager,运行以下命令。 管理节点会指示工作节点自动移除网络。

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

5.3 使用用户定义的覆盖网络

先决条件

假设群已经设置好,并且你在管理节点。

实践

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

```bash
$ docker network create -d overlay my-overlay
```

2. 使用覆盖网络启动服务,并将端口80发布到 Docker 主机上的端口8080。

```bash
$ 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. 删除服务和网络。

```bash
$ docker service rm my-nginx

$ docker network rm my-overlay
```

5.4 对独立容器使用覆盖网络

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

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

先决条件

对于这个测试,您需要两个可以相互通信的 Docker 主机。 每个主机必须具有 Docker 17.06或更高版本,并在两个 Docker 主机之间打开以下端口:

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

一种简单的设置方法是使用两个 vm (本地或像 AWS 这样的云提供商) ,每个 vm 都安装并运行了 Docker。 如果您正在使用 AWS 或类似的云计算平台,最简单的配置是使用一个安全组来打开两台主机之间的所有传入端口,并从客户机的 IP 地址打开 SSH 端口。

这个例子将我们的群中的两个节点称为 host1和 host2。 这个示例也使用 Linux 主机,但是相同的命令可以在 Windows 上使用。

实践

  1. 设置集群

    a. 在 host1上,初始化一个群(如果提示,使用 -- advertised-addr 为与群中其他主机通信的接口指定 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.

    如果节点未能加入群体,docker 群体将超时加入命令。 要解决这个问题,运行 docker swarm leave ——强制 host2,验证网络和防火墙设置,然后再试一次。

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

    $ 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 上,ping alpine2alpine1的交互终端上:

    / # 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 容器,你可以从 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 就会消失。

    在 host2上,停止使用 alpine2,检查测试网是否被移除,然后移除 alpine2:

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

    在 host1上,删除 alpine1和 test-net:

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

5.5 容器和群服务之间的通信

先决条件

本例中需要 Docker 17.06或更高版本。

实践

在本例中,您在同一个 Docker 主机上启动两个不同的 alpine 容器,并进行一些测试以了解它们如何彼此通信。 您需要安装并运行 Docker。

  1. 打开终端窗口。 在你做任何事情之前列出当前的网络。 如果您从未在这个 Docker 守护进程上添加过网络或初始化过一个群,下面是您应该看到的内容。 你可能会看到不同的网络,但是你至少应该看到这些(网络 id 不同) :

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    17e324f45964        bridge              bridge              local
    6ed54d316334        host                host                local
    7092879f2cc8        none                null                local
    

    列出了缺省桥接网络、主机和 none。 后两者不是完全成熟的网络,但用于启动直接连接到 Docker 守护进程主机的网络堆栈的容器,或者启动没有网络设备的容器。 本教程将把两个容器连接到桥接网络。

  2. 启动两个运行阿尔卑斯灰的容器,这是阿尔卑斯的默认外壳而不是猛击。 Dit 标志意味着启动分离的容器(在后台)、交互式的容器(可以在其中键入内容)和 TTY (这样您就可以看到输入和输出)。 因为是分离启动的,所以不会马上连接到容器。 相反,容器的 ID 将被打印出来。 因为您没有指定任何 – 网络标志,所以容器连接到默认的网桥网络。

    $ docker run -dit --name alpine1 alpine ash
    
    $ docker run -dit --name alpine2 alpine ash

    检查两个容器是否实际启动:

    $ docker container ls
    
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    602dbf1edc81        alpine              "ash"               4 seconds ago       Up 3 seconds                            alpine2
    da33b7aa74b0        alpine              "ash"               17 seconds ago      Up 16 seconds  
  3. 检查桥接网络,看看有哪些容器连接到它。

    $ docker network inspect bridge
    
    [
     {
         "Name": "bridge",
         "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
         "Created": "2017-06-22T20:27:43.826654485Z",
         "Scope": "local",
         "Driver": "bridge",
         "EnableIPv6": false,
         "IPAM": {
             "Driver": "default",
             "Options": null,
             "Config": [
                 {
                     "Subnet": "172.17.0.0/16",
                     "Gateway": "172.17.0.1"
                 }
             ]
         },
         "Internal": false,
         "Attachable": false,
         "Containers": {
             "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
                 "Name": "alpine2",
                 "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
                 "MacAddress": "02:42:ac:11:00:03",
                 "IPv4Address": "172.17.0.3/16",
                 "IPv6Address": ""
             },
             "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
                 "Name": "alpine1",
                 "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
                 "MacAddress": "02:42:ac:11:00:02",
                 "IPv4Address": "172.17.0.2/16",
                 "IPv6Address": ""
             }
         },
         "Options": {
             "com.docker.network.bridge.default_bridge": "true",
             "com.docker.network.bridge.enable_icc": "true",
             "com.docker.network.bridge.enable_ip_masquerade": "true",
             "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
             "com.docker.network.bridge.name": "docker0",
             "com.docker.network.driver.mtu": "1500"
         },
         "Labels": {}
     }
    ]

    在顶部附近,列出了有关桥接网络的信息,包括 Docker 主机和桥接网络之间网关的 IP 地址(172.17.0.1)。 在 Containers 键下,列出了每个连接的容器,以及有关其 IP 地址的信息(alpine1为172.17.0.2,alpine2为172.17.0.3)。

  4. 容器在后台运行。使用 docker attach 命令连接到 alpine1

    $ docker attach alpine1
    
    / #
    

    提示将更改为 # ,以指示您是容器中的根用户。 使用 ip addr show 命令显示 alpine1的网络接口,因为它们从容器内部观察:

    # ip addr show
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
     inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
     inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
    27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
     link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
     inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
     inet6 fe80::42:acff:fe11:2/64 scope link
       valid_lft forever preferred_lft forever

    第一个接口是环回设备。 暂时忽略它。 请注意,第二个接口的 IP 地址为172.17.0.2,与前面步骤中显示的 alpine1的地址相同。

  5. alpine1 内部,确保你可以通过 ping google.com 连接到互联网。 -c 2 标志将命令限制为两次 ping 尝试。

    # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 data bytes
    64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms
    64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms
    
    \--- google.com ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 9.841/9.869/9.897 ms
  6. 现在尝试 ping 第二个容器,首先,ping 它的 IP 地址,172.17.0.3:

    # ping -c 2 172.17.0.3
    
    PING 172.17.0.3 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
    64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms
    
    \--- 172.17.0.3 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 0.086/0.090/0.094 ms

    成功。接下来,尝试按容器名称 ping alpine2容器。这将失败。

    # ping -c 2 alpine2
    
    ping: bad address 'alpine2'
  7. 通过使用分离序列,CTRL + p CTRL + q (按住 CTRL,输入 p 后跟 q)从 alpine1中分离,而不停止它。 如果你愿意,连接到 alpine2,重复步骤4,5,6,用 alpine1代替 alpine2

  8. 停止并移走两个容器。

    $ docker container stop alpine1 alpine2
    $ docker container rm alpine1 alpine2

    请记住,生产环境中不推荐使用默认的网桥网络。 要了解用户定义的桥梁网络,请继续阅读下一个教程。


文章作者: Baymax
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Baymax !
评论
 上一篇
Docker入门系列  7. Docker 容器网络的概念及网络配置 主机网络 Docker入门系列 7. Docker 容器网络的概念及网络配置 主机网络
1. 使用主机网络如果您使用容器的主机网络模式,那么容器的网络堆栈不会与 Docker 主机隔离(容器共享主机的网络名称空间) ,并且容器不会得到自己的 ip 地址分配。 例如,如果您运行一个绑定到端口80的容器,并且使用主机网络,那么容器
2020-05-25
下一篇 
Docker入门系列  4. Docker 容器网络的概念及网络配置 网桥网络 Docker入门系列 4. Docker 容器网络的概念及网络配置 网桥网络
1. 使用网桥网络就网络而言,桥接网络是在网段之间转发流量的链路层设备。桥接器可以是在主机内核中运行的硬件设备或软件设备。 就 Docker 而言,桥接网络使用一个软件桥接器,它允许连接到同一桥接网络的容器进行通信,同时提供与未连接到桥接网
2020-05-22
  目录