当前位置:   article > 正文

Docker网络教程(一)bridge 网络教程_adding interface vethf26d525 to bridge docker0 fai

adding interface vethf26d525 to bridge docker0 failed: device does not exist

独立容器的联网

本系列的教程涉及独立 Docker 容器的联网问题。关于与swarm服务的联网,请参阅 Swarm服务的联网教程。如果想了解更多 Docker 网络的理论知识,参考概述

本主题包括三个不同的教程。你可以在Linux、Windows或Mac上运行它们中的每一个,但对于后两种操作系统,你需要在其他地方运行第二个Docker主机。

  • 下面的例子里, 使用默认的 bridge 网络演示了如何使用Docker 为你自动设置的默认 bridge 网络。但这个网络并不是生产环境下的最佳选择。

  • 下面使用用户定义的 bridge 网络展示了如何创建和使用自己的自定义 bridge 网络,以连接运行在同一Docker主机上的容器。在生产环境中运行的独立容器建议使用。

虽然  overlay 网络 通常用于swarm服务,但你也可以将它用于独立的容器。 overlay 网络教程 会有介绍。

使用默认的 bridge 网络

在这个例子中,你在同一台 Docker 宿主机上启动两个不同的 alpine 容器,并做一些测试,以了解它们如何相互通信。你需要安装并运行 Docker。

  1. 打开一个终端窗口。在你做其他事情之前,列出当前的网络。如果你从未在这个Docker daemon 上添加过网络或初始化过swarm,你应该看到以下内容。你可能会看到不同的网络,但你至少应该看到这些(网络ID会不同):

    1. $ docker network ls
    2. NETWORK ID NAME DRIVER SCOPE
    3. 17e324f45964 bridge bridge local
    4. 6ed54d316334 host host local
    5. 7092879f2cc8 none null local

    默认的 bridge 网络、 host 跟 none 在上面列了出来。后两者不是 “完整” 的网络,而是用来启动直接连接到 Docker daemon 宿主机协议栈,又或者是启动没有网络设备的容器的。本教程将把两个容器连接到 bridge 网络

  2. 启动两个运行 ash的 alpine 容器,ash是 Alpine 的默认 shell 而不是 bash。 -dit 标志意味着启动 detached 方式的、(即后台运行)、交互式的(能够向其中输入文字)和TTY(所以你可以看到输入和输出)容器。由于你是以 detached 方式启动的,所以你不会立即与容器连接。相反,容器的ID将被打印出来。因为你没有指定任何 --network 标志,所以容器会连接到默认的 bridge 网络。

    1. $ docker run -dit --name alpine1 alpine ash
    2. $ docker run -dit --name alpine2 alpine ash

    检查两个启动的容器:

    1. $ docker container ls
    2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    3. 602dbf1edc81 alpine "ash" 4 seconds ago Up 3 seconds alpine2
    4. da33b7aa74b0 alpine "ash" 17 seconds ago Up 16 seconds alpine1
  3. Inspect 一下 bridge 网络,看看连接的容器:

    1. $ docker network inspect bridge
    2. [
    3. {
    4. "Name": "bridge",
    5. "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
    6. "Created": "2017-06-22T20:27:43.826654485Z",
    7. "Scope": "local",
    8. "Driver": "bridge",
    9. "EnableIPv6": false,
    10. "IPAM": {
    11. "Driver": "default",
    12. "Options": null,
    13. "Config": [
    14. {
    15. "Subnet": "172.17.0.0/16",
    16. "Gateway": "172.17.0.1"
    17. }
    18. ]
    19. },
    20. "Internal": false,
    21. "Attachable": false,
    22. "Containers": {
    23. "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
    24. "Name": "alpine2",
    25. "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
    26. "MacAddress": "02:42:ac:11:00:03",
    27. "IPv4Address": "172.17.0.3/16",
    28. "IPv6Address": ""
    29. },
    30. "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
    31. "Name": "alpine1",
    32. "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
    33. "MacAddress": "02:42:ac:11:00:02",
    34. "IPv4Address": "172.17.0.2/16",
    35. "IPv6Address": ""
    36. }
    37. },
    38. "Options": {
    39. "com.docker.network.bridge.default_bridge": "true",
    40. "com.docker.network.bridge.enable_icc": "true",
    41. "com.docker.network.bridge.enable_ip_masquerade": "true",
    42. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
    43. "com.docker.network.bridge.name": "docker0",
    44. "com.docker.network.driver.mtu": "1500"
    45. },
    46. "Labels": {}
    47. }
    48. ]

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

  4. 容器们都在后台跑着。用 docker attach 命令连接 alpine1.

    1. $ docker attach alpine1
    2. / #

    提示符变成了 # ,表示你是容器内的 root 用户。使用 ip addr show 命令来显示 alpine1 的网络接口,如下:

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

    第一个接口时环回(loopback)设备,暂时忽略它。注意第二个IP是 172.17.0.2的接口,此IP跟上面显示的 alpine1 信息是一致的。

  5. 在 alpine1中,确保你能通过ping  baidu.com连接到互联网。 -c 2 标志限制了该命令的两次 ping 尝试。

    1. # ping -c 2 baidu.com
    2. PING baidu.com (110.242.68.66) 56(84) bytes of data.
    3. 64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=1 ttl=49 time=42.8 ms
    4. 64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=2 ttl=49 time=42.6 ms
    5. --- baidu.com ping statistics ---
    6. 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
    7. rtt min/avg/max/mdev = 42.699/42.777/42.855/0.078 ms
  6. 现在常识ping第二个容器。首先,用它的 IP 地址 172.17.0.3去ping:

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

    成功。接着,尝试用 alpine2 的容器名去 ping,这会失败。

    1. # ping -c 2 alpine2
    2. ping: bad address 'alpine2'
  7. 通过使用 detach 序列, CTRL + p CTRL + q (按住 CTRL 键,输入 p ,然后输入q),在不停止 alpine1的情况下从其 detach 。如果你愿意,可以连接到 alpine2 ,在那里重复步骤4、5和6,用 alpine1 代替 alpine2

  8. 停掉并删除两个容器。

    1. $ docker container stop alpine1 alpine2
    2. $ docker container rm alpine1 alpine2

记住,默认的 bridge 网络不建议用在生产环境里。想了解更多的用户定义 bridge 网络,请接着往下看。

使用用户定义 bridge 网络

在这个例子中,我们再次启动了两个 alpine 容器,但不同的是,我们把它们连接到我们已经创建的一个叫做 alpine-net 网络的用户定义的网络。这些容器没有连接到默认的 bridge 网络。然后我们启动第三个 alpine 容器,它连接到 bridge 网络,但没有连接到 alpine-net,第四个 alpine 容器则同时连接到两个网络。

  1. 创建 alpine-net 网络。你不需要用 --driver bridge 标志来指定使用的是 bridge 驱动,因为 bridge 就是默认的方式。但例子里还是展示了如何指定它。

    $ docker network create --driver bridge alpine-net
    
  2. 列出 Docker 的网络:

    1. $ docker network ls
    2. NETWORK ID NAME DRIVER SCOPE
    3. e9261a8c9a19 alpine-net bridge local
    4. 17e324f45964 bridge bridge local
    5. 6ed54d316334 host host local
    6. 7092879f2cc8 none null local

    Inspect 一下 alpine-net 网络。下面展示了它的 IP 地址以及还未有容器连接他的现状:

    1. $ docker network inspect alpine-net
    2. [
    3. {
    4. "Name": "alpine-net",
    5. "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
    6. "Created": "2017-09-25T21:38:12.620046142Z",
    7. "Scope": "local",
    8. "Driver": "bridge",
    9. "EnableIPv6": false,
    10. "IPAM": {
    11. "Driver": "default",
    12. "Options": {},
    13. "Config": [
    14. {
    15. "Subnet": "172.18.0.0/16",
    16. "Gateway": "172.18.0.1"
    17. }
    18. ]
    19. },
    20. "Internal": false,
    21. "Attachable": false,
    22. "Containers": {},
    23. "Options": {},
    24. "Labels": {}
    25. }
    26. ]

    注意这网络的网关为 172.18.0.1, 相对的,默认的 bridge 网络的网关是 172.17.0.1。确切的IP地址可能在你的机器上会有所不同。

  3. 创建你的容器。注意 --network 标志。在运行 docker run 命令的时候只能连接到一个网络。所以你需要在之后使用 docker network connect ,将 alpine4 也连接到 bridge 网络。

    1. $ docker run -dit --name alpine1 --network alpine-net alpine ash
    2. $ docker run -dit --name alpine2 --network alpine-net alpine ash
    3. $ docker run -dit --name alpine3 alpine ash
    4. $ docker run -dit --name alpine4 --network alpine-net alpine ash
    5. $ docker network connect bridge alpine4

    验证一下所有的容器都已经在运行:

    1. $ docker container ls
    2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    3. 156849ccd902 alpine "ash" 41 seconds ago Up 41 seconds alpine4
    4. fa1340b8d83e alpine "ash" 51 seconds ago Up 51 seconds alpine3
    5. a535d969081e alpine "ash" About a minute ago Up About a minute alpine2
    6. 0a02c449a6e9 alpine "ash" About a minute ago Up About a minute alpine1
  4. 再次 Inspect 一下 bridge 网络跟 alpine-net 网络:

    1. $ docker network inspect bridge
    2. [
    3. {
    4. "Name": "bridge",
    5. "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
    6. "Created": "2017-06-22T20:27:43.826654485Z",
    7. "Scope": "local",
    8. "Driver": "bridge",
    9. "EnableIPv6": false,
    10. "IPAM": {
    11. "Driver": "default",
    12. "Options": null,
    13. "Config": [
    14. {
    15. "Subnet": "172.17.0.0/16",
    16. "Gateway": "172.17.0.1"
    17. }
    18. ]
    19. },
    20. "Internal": false,
    21. "Attachable": false,
    22. "Containers": {
    23. "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
    24. "Name": "alpine4",
    25. "EndpointID": "7277c5183f0da5148b33d05f329371fce7befc5282d2619cfb23690b2adf467d",
    26. "MacAddress": "02:42:ac:11:00:03",
    27. "IPv4Address": "172.17.0.3/16",
    28. "IPv6Address": ""
    29. },
    30. "fa1340b8d83eef5497166951184ad3691eb48678a3664608ec448a687b047c53": {
    31. "Name": "alpine3",
    32. "EndpointID": "5ae767367dcbebc712c02d49556285e888819d4da6b69d88cd1b0d52a83af95f",
    33. "MacAddress": "02:42:ac:11:00:02",
    34. "IPv4Address": "172.17.0.2/16",
    35. "IPv6Address": ""
    36. }
    37. },
    38. "Options": {
    39. "com.docker.network.bridge.default_bridge": "true",
    40. "com.docker.network.bridge.enable_icc": "true",
    41. "com.docker.network.bridge.enable_ip_masquerade": "true",
    42. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
    43. "com.docker.network.bridge.name": "docker0",
    44. "com.docker.network.driver.mtu": "1500"
    45. },
    46. "Labels": {}
    47. }
    48. ]

    容器 alpine3 跟 alpine4 了解到了 bridge 网络

    1. $ docker network inspect alpine-net
    2. [
    3. {
    4. "Name": "alpine-net",
    5. "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
    6. "Created": "2017-09-25T21:38:12.620046142Z",
    7. "Scope": "local",
    8. "Driver": "bridge",
    9. "EnableIPv6": false,
    10. "IPAM": {
    11. "Driver": "default",
    12. "Options": {},
    13. "Config": [
    14. {
    15. "Subnet": "172.18.0.0/16",
    16. "Gateway": "172.18.0.1"
    17. }
    18. ]
    19. },
    20. "Internal": false,
    21. "Attachable": false,
    22. "Containers": {
    23. "0a02c449a6e9a15113c51ab2681d72749548fb9f78fae4493e3b2e4e74199c4a": {
    24. "Name": "alpine1",
    25. "EndpointID": "c83621678eff9628f4e2d52baf82c49f974c36c05cba152db4c131e8e7a64673",
    26. "MacAddress": "02:42:ac:12:00:02",
    27. "IPv4Address": "172.18.0.2/16",
    28. "IPv6Address": ""
    29. },
    30. "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
    31. "Name": "alpine4",
    32. "EndpointID": "058bc6a5e9272b532ef9a6ea6d7f3db4c37527ae2625d1cd1421580fd0731954",
    33. "MacAddress": "02:42:ac:12:00:04",
    34. "IPv4Address": "172.18.0.4/16",
    35. "IPv6Address": ""
    36. },
    37. "a535d969081e003a149be8917631215616d9401edcb4d35d53f00e75ea1db653": {
    38. "Name": "alpine2",
    39. "EndpointID": "198f3141ccf2e7dba67bce358d7b71a07c5488e3867d8b7ad55a4c695ebb8740",
    40. "MacAddress": "02:42:ac:12:00:03",
    41. "IPv4Address": "172.18.0.3/16",
    42. "IPv6Address": ""
    43. }
    44. },
    45. "Options": {},
    46. "Labels": {}
    47. }
    48. ]

    容器 alpine1alpine2 跟 alpine4 连接到了 alpine-net 网络。

  5. 在像 alpine-net这样的用户定义的网络上,容器之间不仅可以通过IP地址进行通信,而且还可以将容器名称解析为IP地址。这种能力被称为自动服务发现(automatic service discovery),类似于局域网的主机名通讯。让我们连接到 alpine1 并测试一下。 alpine1 应该能够将 alpine2 和 alpine4(以及 alpine1本身)解析为IP地址。

    1. $ docker container attach alpine1
    2. # ping -c 2 alpine2
    3. PING alpine2 (172.18.0.3): 56 data bytes
    4. 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms
    5. 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.090 ms
    6. --- alpine2 ping statistics ---
    7. 2 packets transmitted, 2 packets received, 0% packet loss
    8. round-trip min/avg/max = 0.085/0.087/0.090 ms
    9. # ping -c 2 alpine4
    10. PING alpine4 (172.18.0.4): 56 data bytes
    11. 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.076 ms
    12. 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.091 ms
    13. --- alpine4 ping statistics ---
    14. 2 packets transmitted, 2 packets received, 0% packet loss
    15. round-trip min/avg/max = 0.076/0.083/0.091 ms
    16. # ping -c 2 alpine1
    17. PING alpine1 (172.18.0.2): 56 data bytes
    18. 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.026 ms
    19. 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.054 ms
    20. --- alpine1 ping statistics ---
    21. 2 packets transmitted, 2 packets received, 0% packet loss
    22. round-trip min/avg/max = 0.026/0.040/0.054 ms
  6. 你应该从 alpine1 连接不到 alpine3 ,因为  alpine3 没有连接到alpine-net 网络。

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

    不止如此,你也不能从 alpine1 用IP地址连接到  alpine3 。看回 docker network inspect 有关于 bridge 网络的输出,找到 alpine3的IP地址 172.17.0.2 然后尝试连接它:

    1. # ping -c 2 172.17.0.2
    2. PING 172.17.0.2 (172.17.0.2): 56 data bytes
    3. --- 172.17.0.2 ping statistics ---
    4. 2 packets transmitted, 0 packets received, 100% packet loss

    用 Detach 操作序列从 alpine1 断开, CTRL + p CTRL + q (按下 CTRL 然后依次键入 p 、 q)。

  7. 记得,alpine4 同时连接了默认的 bridge 跟 alpine-net,理论上它能连接其他所有的容器。然而对于 alpine3 ,它需要用IP地址来定位,并不能用容器名。连接它并跑一下测试。

    1. $ docker container attach alpine4
    2. # ping -c 2 alpine1
    3. PING alpine1 (172.18.0.2): 56 data bytes
    4. 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
    5. 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms
    6. --- alpine1 ping statistics ---
    7. 2 packets transmitted, 2 packets received, 0% packet loss
    8. round-trip min/avg/max = 0.074/0.078/0.082 ms
    9. # ping -c 2 alpine2
    10. PING alpine2 (172.18.0.3): 56 data bytes
    11. 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms
    12. 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms
    13. --- alpine2 ping statistics ---
    14. 2 packets transmitted, 2 packets received, 0% packet loss
    15. round-trip min/avg/max = 0.075/0.077/0.080 ms
    16. # ping -c 2 alpine3
    17. ping: bad address 'alpine3'
    18. # ping -c 2 172.17.0.2
    19. PING 172.17.0.2 (172.17.0.2): 56 data bytes
    20. 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.089 ms
    21. 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
    22. --- 172.17.0.2 ping statistics ---
    23. 2 packets transmitted, 2 packets received, 0% packet loss
    24. round-trip min/avg/max = 0.075/0.082/0.089 ms
    25. # ping -c 2 alpine4
    26. PING alpine4 (172.18.0.4): 56 data bytes
    27. 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.033 ms
    28. 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.064 ms
    29. --- alpine4 ping statistics ---
    30. 2 packets transmitted, 2 packets received, 0% packet loss
    31. round-trip min/avg/max = 0.033/0.048/0.064 ms
  8. 作为最后的测试,确保你的容器都能通过ping baidu.com连接到互联网。既然你已经连接到了 alpine4 ,那么我们从那里开始尝试。接下来,从 alpine4 分离并连接到 alpine3 (它只连接到 bridge 网络)并再次尝试。最后,连接到 alpine1 (它只连接到 alpine-net 网络),再试一次。

    1. # ping -c 2 baidu.com
    2. PING baidu.com (110.242.68.66): 56 data bytes
    3. 64 bytes from 110.242.68.66: seq=0 ttl=41 time=9.778 ms
    4. 64 bytes from 110.242.68.66: seq=1 ttl=41 time=9.634 ms
    5. --- baidu.com ping statistics ---
    6. 2 packets transmitted, 2 packets received, 0% packet loss
    7. round-trip min/avg/max = 9.634/9.706/9.778 ms
    8. CTRL+p CTRL+q
    9. $ docker container attach alpine3
    10. # ping -c 2 baidu.com
    11. PING baidu.com (110.242.68.66): 56 data bytes
    12. 64 bytes from 110.242.68.66: seq=0 ttl=41 time=9.706 ms
    13. 64 bytes from 110.242.68.66: seq=1 ttl=41 time=9.851 ms
    14. --- baidu.com ping statistics ---
    15. 2 packets transmitted, 2 packets received, 0% packet loss
    16. round-trip min/avg/max = 9.706/9.778/9.851 ms
    17. CTRL+p CTRL+q
    18. $ docker container attach alpine1
    19. # ping -c 2 baidu.com
    20. PING baidu.com (110.242.68.66): 56 data bytes
    21. 64 bytes from 110.242.68.66: seq=0 ttl=41 time=9.606 ms
    22. 64 bytes from 110.242.68.66: seq=1 ttl=41 time=9.603 ms
    23. --- baidu.com ping statistics ---
    24. 2 packets transmitted, 2 packets received, 0% packet loss
    25. round-trip min/avg/max = 9.603/9.604/9.606 ms
    26. CTRL+p CTRL+q
  9. 停止并删除所有容器以及 alpine-net 网络。

    1. $ docker container stop alpine1 alpine2 alpine3 alpine4
    2. $ docker container rm alpine1 alpine2 alpine3 alpine4
    3. $ docker network rm alpine-net

其他的网络教程

现在你已经完成了独立容器的网络教程,你可能想跑一下其他的:

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号