使用獨立容器進行網路連線
本系列教程介紹了獨立 Docker 容器的網路連線。有關使用 swarm 服務進行網路連線的資訊,請參見 使用 swarm 服務進行網路連線。如果您需要詳細瞭解 Docker 網路,請參見 概述。
本主題包含兩個不同的教程。您可以在 Linux、Windows 或 Mac 上執行每個教程,但最後一個教程需要在其他位置執行第二個 Docker 主機。
使用預設橋接網路 演示瞭如何使用 Docker 自動為您設定的預設
bridge網路。此網路不是生產系統的最佳選擇。使用使用者定義的橋接網路 展示瞭如何建立和使用您自己的自定義橋接網路,以連線執行在同一 Docker 主機上的容器。建議在生產環境中執行的獨立容器使用此方法。
雖然 overlay 網路 通常用於 swarm 服務,但您也可以將 overlay 網路用於獨立容器。這包含在 使用 overlay 網路的教程 中。
使用預設橋接網路
在本示例中,您在同一 Docker 主機上啟動了兩個不同的 alpine 容器並進行了一些測試,以瞭解它們如何相互通訊。您需要安裝並執行 Docker。
開啟一個終端視窗。在執行任何操作之前列出當前網路。如果您從未新增過網路或在此 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網路。啟動兩個執行
ash的alpine容器,ash是 Alpine 的預設 shell,而不是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檢查
bridge網路以檢視哪些容器連線到它。$ 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網路之間的閘道器的 IP 地址(172.17.0.1)。在Containers金鑰下,列出了每個連線的容器以及有關其 IP 地址的資訊(alpine1為172.17.0.2,alpine2為172.17.0.3)。容器正在後臺執行。使用
docker attach命令連線到alpine1。$ docker attach alpine1 / #提示符更改為
#,表示您是容器中的root使用者。使用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的地址相同。在
alpine1中,確保您可以透過 pinggoogle.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現在嘗試 ping 第二個容器。首先,透過其 IP 地址
172.17.0.3ping 它# 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'使用分離序列
CTRL+pCTRL+q從alpine1分離,而不會停止它(按住CTRL並依次鍵入p和q)。如果您願意,可以連線到alpine2並重復步驟 4、5 和 6,將alpine1替換為alpine2。停止並刪除兩個容器。
$ docker container stop alpine1 alpine2 $ docker container rm alpine1 alpine2
請記住,預設的 bridge 網路不建議用於生產環境。若要了解使用者定義的橋接網路,請繼續到 下一個教程。
使用使用者定義的橋接網路
在本示例中,我們再次啟動了兩個 alpine 容器,但將它們連線到一個名為 alpine-net 的使用者定義網路,我們已經建立了該網路。這些容器根本沒有連線到預設的 bridge 網路。然後,我們啟動了第三個 alpine 容器,該容器連線到 bridge 網路,但沒有連線到 alpine-net,以及第四個 alpine 容器,該容器連線到兩個網路。
建立
alpine-net網路。您不需要--driver bridge標誌,因為它是預設標誌,但本示例演示瞭如何指定它。$ docker network create --driver bridge alpine-net列出 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不同。確切的 IP 地址在您的系統上可能不同。建立四個容器。注意
--network標誌。您只能在docker run命令期間連線到一個網路,因此您需要使用docker network connect之後才能將alpine4連線到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再次檢查
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網路。在
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從
alpine1開始,您應該根本無法連線到alpine3,因為它不在alpine-net網路上。# ping -c 2 alpine3 ping: bad address 'alpine3'不僅如此,您還無法透過其 IP 地址從
alpine1連線到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使用分離序列
CTRL+pCTRL+q從alpine1分離(按住CTRL並依次鍵入p和q)。請記住,
alpine4連線到預設的bridge網路和alpine-net。它應該能夠訪問所有其他容器。但是,您需要透過其 IP 地址訪問alpine3。連線到它並執行測試。$ 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作為最終測試,確保您的容器都可以透過 ping
google.com連線到網際網路。您已經連線到alpine4,因此首先嚐試從那裡進行。接下來,從alpine4分離並連線到alpine3(它只連線到bridge網路)並再次嘗試。最後,連線到alpine1(它只連線到alpine-net網路)並再次嘗試。# 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停止並刪除所有容器和
alpine-net網路。$ docker container stop alpine1 alpine2 alpine3 alpine4 $ docker container rm alpine1 alpine2 alpine3 alpine4 $ docker network rm alpine-net