欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

Docker 配置网络教程 - bridge 网络

程序员文章站 2022-03-23 19:44:50
Docker 配置网络教程 - bridge 网络,本系列教程涉及独立 Docker 容器的网络。有关 swarm 服务的网络。 这个主题包括三个不同的教程。你可以在 Linux,Windo...

Docker 配置网络教程 - bridge 网络,本系列教程涉及独立 Docker 容器的网络。有关 swarm 服务的网络。

这个主题包括三个不同的教程。你可以在 Linux,Windows 或 Mac 上运行每一个教程,但对于最后两个,需要一个在别处运行的第二个 Docker 主机。

使用默认的 bridge 网络演示了如何使用 Docker 会自动设置的默认 bridge 网络。对于生产环境来说,这个网络不是最佳选择。 使用用户自定义的 bridge 网络包含如何创建和使用你的自定义 bridge 网络,来连接同一个 Docker 主机上运行的多个容器。生产环境中运行的独立容器建议使用这种方式。

虽然 overlay 网络通常用于 swarm 服务,Docker 17.06 或更高版本允许你在独立容器中使用 overlay 网络。这会在 overlay 网络教程 中讲解。

1. 使用默认的 bridge 网络

在这个例子中需要在同一个 Docker 主机上开启两个不同的 alpine 容器,做些测试来理解这两个容器是如何互相通信的。

1.1 打开终端窗口

在进行下一步之前先列出当前的网络。如果你没有在这个 Docker 守护进程中添加网络或初始化 swarm,那应该看到下面的内容。可能会看到不同的网络,但至少要有这些(网络 ID 会有所不同):

$ docker network ls

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

默认的 bridge 网络和 host、none 一同列出。后两者不是完全成熟的网络,而是用于启动直接连接到 Docker 守护进程主机的网络堆栈的容器,或者启动没有网络设备的容器。本教程将两个容器连接到 bridge 网络。

1.2 开启两个容器

开启两个运行 ash 的 alpine 容器,Alpine 的默认脚本工具是 ash 而不是 bash。-dit 标志意味着后台模式,交互式(有能力输入),并且有 TTY(因此可以看见输入和输出)来启动这个容器。由于是后台模式启动容器,所以不会立即连接到容器。相反,容器的 ID 将被打印出来。由于没有指定任何 --network 标志,因此容器将连接到默认 bridge 网络。

$ 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                           alpine1

1.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": {}
    }
]

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

1.4 使用 docker attach 命令连接到后台运行的容器

$ docker attach alpine1

/ #

提示符变为 #,表示你现在是容器中的 root 用户了。使用 ip addr show 命令来从容器内查看 alpine1 的网络接口:

# ip addr show

1: lo:  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:  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 的地址一样。

1.5 在 alpine1 中确保可以联网

通过 ping baidu.com,在 alpine1 中确保已经联网了。-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

1.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

成功了。然后,尝试通过容器名 alpine2 来 ping。这会失败。

# ping -c 2 alpine2

ping: bad address 'alpine2'

1.7 依次按下 CTRL + p 和 CTRL + q(按住CTRL并键入p,然后键入q),使 alpine1 转到后台运行而不停止。

1.8 停止并删除所有容器

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

注意,生产环境中不建议使用默认的 bridge 网络。

2. 使用用户自定义的 bridge 网络

下面的例子还是需要启动两个 alpine 容器,但是会连接到名为 alpine-net 的用户自定义网络。这些容器不会再连接到默认的 bridge 网络。然后我们启动第三个已经连接到 bridge 网络但是没有连接到 alpine-net 的 alpine 容器,第四个已经连接到所有网络的 alpine 容器。

2.1 创建 alpine-net 网络。

不需要 --driver bridge 标志,因为这是默认的,但是这个例子展示了如何使用。

$ docker network create --driver bridge alpine-net

2.2 列出 Docker 的网络:

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
e9261a8c9a19        alpine-net          bridge              local
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local

检查这个 alpine-net 网络。这会向你显示其 IP 地址以及未连接容器的事实:

$ docker network inspect alpine-net

[
    {
        "Name": "alpine-net",
        "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
        "Created": "2017-09-25T21:38:12.620046142Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

注意这个网络的网关是 172.18.0.1,暴露到网关为 172.17.0.1 的默认 bridge 网络。

2.3 创建四个容器

注意 --network 标志。通过 docker run 命令只能连接到一个网络,所以需要在创建 alpine4 后使用 docker network attach 将其连接到 bridge 网络。

$ docker run -dit --name alpine1 --network alpine-net alpine ash

$ docker run -dit --name alpine2 --network alpine-net alpine ash

$ docker run -dit --name alpine3 alpine ash

$ docker run -dit --name alpine4 --network alpine-net alpine ash

$ docker network connect bridge alpine4

验证所有的容器都在运行:

$ docker container ls

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
156849ccd902        alpine              "ash"               41 seconds ago       Up 41 seconds                           alpine4
fa1340b8d83e        alpine              "ash"               51 seconds ago       Up 51 seconds                           alpine3
a535d969081e        alpine              "ash"               About a minute ago   Up About a minute                       alpine2
0a02c449a6e9        alpine              "ash"               About a minute ago   Up About a minute                       alpine1

2.4 再次检查 bridge 网络和 alpine-net 网络

$ 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": {
            "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                "Name": "alpine4",
                "EndpointID": "7277c5183f0da5148b33d05f329371fce7befc5282d2619cfb23690b2adf467d",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "fa1340b8d83eef5497166951184ad3691eb48678a3664608ec448a687b047c53": {
                "Name": "alpine3",
                "EndpointID": "5ae767367dcbebc712c02d49556285e888819d4da6b69d88cd1b0d52a83af95f",
                "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": {}
    }
]

容器 alpine3 和 alpine4 已经连接到了 bridge 网络:

$ docker network inspect alpine-net

[
    {
        "Name": "alpine-net",
        "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
        "Created": "2017-09-25T21:38:12.620046142Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "0a02c449a6e9a15113c51ab2681d72749548fb9f78fae4493e3b2e4e74199c4a": {
                "Name": "alpine1",
                "EndpointID": "c83621678eff9628f4e2d52baf82c49f974c36c05cba152db4c131e8e7a64673",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                "Name": "alpine4",
                "EndpointID": "058bc6a5e9272b532ef9a6ea6d7f3db4c37527ae2625d1cd1421580fd0731954",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "a535d969081e003a149be8917631215616d9401edcb4d35d53f00e75ea1db653": {
                "Name": "alpine2",
                "EndpointID": "198f3141ccf2e7dba67bce358d7b71a07c5488e3867d8b7ad55a4c695ebb8740",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

容器 alpine1,alpine2 和 alpine4 已经连接到了 alpine-net 网络。

2.5 自动服务探测

alpine-net 类似的用户自定义网络上,容器可以通过 IP 地址或 IP 地址对应的容器名进行通信。这个能力称作自动服务探测。让我们连接到 alpine1 来测试一下。alpine1 应该可以解析 alpine2 和 alpine4 (包括 alpine1 自身)为 IP 地址。

$ docker container attach alpine1

# ping -c 2 alpine2

PING alpine2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.090 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.085/0.087/0.090 ms

# ping -c 2 alpine4

PING alpine4 (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.076 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.091 ms

--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.076/0.083/0.091 ms

# ping -c 2 alpine1

PING alpine1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.026 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.054 ms

--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.026/0.040/0.054 ms

2.6 alpine1 不可连接到 alpine-net,因为它并不在 alpine1 网络上

# ping -c 2 alpine3

ping: bad address 'alpine3'

不仅如此,也无法从 alpine1 通过其 IP 地址连接到到 alpine3。回头看看 bridge 网络的 docker network inspect 命令下的输出,并找到 alpine3 的 IP 地址:172.17.0.2 尝试 ping 它。

# ping -c 2 172.17.0.2

PING 172.17.0.2 (172.17.0.2): 56 data bytes

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

使 alpine1 转入后台运行(CTRL + p CTRL + q,按住 CTRL 并依次按下 p 和 q)。

2.7 测试 alpine4

alpine4 连接到默认的 bridge 网络和 alpine-net 网络。它应该可以访问所有容器。然而,对于 alpine3 你需要通过 IP 地址访问。

$ docker container attach alpine4

# ping -c 2 alpine1

PING alpine1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms

--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.074/0.078/0.082 ms

# ping -c 2 alpine2

PING alpine2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.075/0.077/0.080 ms

# ping -c 2 alpine3
ping: bad address 'alpine3'

# ping -c 2 172.17.0.2

PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.075/0.082/0.089 ms

# ping -c 2 alpine4

PING alpine4 (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.033 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.064 ms

--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.033/0.048/0.064 ms

2.8 最终测试

通过 pinging baidu.com 确保所有的容器都可以连接到网络。你已经连上 alpine4 了,就从这儿开始。下一步,退出 alpine4,连接 alpine3(这个容器只连接到了 bridge 网络)再次实验。最终,用 alpine1 再次实验。

# 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.778 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.634 ms

--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.634/9.706/9.778 ms

CTRL+p CTRL+q

$ docker container attach alpine3

# 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.706 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.851 ms

--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.706/9.778/9.851 ms

CTRL+p CTRL+q

$ docker container attach alpine1

# 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.606 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.603 ms

--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.603/9.604/9.606 ms

CTRL+p CTRL+q

2.9 停止并删除容器和 alpine-net 网络

$ docker container stop alpine1 alpine2 alpine3 alpine4

$ docker container rm alpine1 alpine2 alpine3 alpine4

$ docker network rm alpine-net