使用橋接網絡
在網絡方面,橋接網絡是鏈路層設備,它在網絡段之間轉發流量。橋接網絡可以是硬件設備或在主機內核中運行的軟件設備。
就Docker而言,橋接網絡使用軟件橋接器,該軟件橋接器允許連接到同一橋接網絡的容器進行通信,同時提供與未連接到該橋接網絡的容器的隔離。Docker橋驅動程序會自動在主機中安裝規則,以便不同橋接網絡上的容器無法直接相互通信。
橋接網絡適用於在同一個 Docker守護程序主機上運行的容器。對於在不同Docker守護程序主機上運行的容器之間的通信,您可以在操作系統級別管理路由,也可以使用覆蓋網絡。
啟動Docker時,會自動創建默認橋接網絡(也稱為bridge
),並且除非另行指定,否則新啟動的容器將連接到該網絡。您還可以創建用戶定義的自定義橋接網絡。用戶定義的橋接網絡 優於默認bridge
網絡。
用戶定義的橋接器可在容器化應用程序之間提供更好的隔離和互操作性
連接到同一個用戶定義的橋接網絡的容器會自動將所有端口相互暴露,而不會向外界顯示任何端口。這使得容器化應用程序可以輕松地相互通信,而不會意外地打開對外界的訪問。
想象一下具有Web前端和數據庫后端的應用程序。外部世界需要訪問Web前端(可能在端口80上),但只有后端本身需要訪問數據庫主機和端口。使用用戶定義的橋接網絡,只需要打開Web端口,並且數據庫應用程序不需要打開任何端口,因為Web前端可以通過用戶定義的橋接網絡訪問它。
如果在默認橋接網絡上運行相同的應用程序堆棧,則需要打開Web端口和數據庫端口,並使用 每個的標記-p
或--publish
標記。這意味着Docker主機需要通過其他方式阻止對數據庫端口的訪問。
用戶定義的橋接器在容器之間提供自動DNS解析
默認橋接網絡上的容器只能通過IP地址相互訪問,除非您使用被認為是過期的的--link
選項。在用戶定義的橋接網絡上,容器可以通過名稱或別名相互解析。
想象一下與前一點相同的應用程序,具有Web前端和數據庫后端。如果你調用容器中的web或者db,Web容器可以在連接到數據庫容器,無論托管在哪個docker 主機,應用程序都會在堆棧上運行。
如果在默認橋接網絡上運行相同的應用程序堆棧,則需要在容器之間手動創建鏈接(使用過期的--link
標志)。這些鏈接需要在兩個方向上創建,因此您可以看到這對於需要通信的兩個以上容器而言變得復雜。或者,您可以操作/etc/hosts
容器中的文件,但這會產生難以調試的問題。
容器可以在運行中與用戶定義的網絡連接和分離
在容器的生命周期中,您可以動態地將其與用戶定義的網絡連接或斷開連接。要從默認橋接網絡中刪除容器,您需要停止容器並使用不同的網絡選項重新創建容器。
每個用戶定義的網絡都會創建一個可配置的橋接網絡
如果容器使用默認橋接網絡,則可以對其進行配置,但所有容器都使用相同的設置,例如MTU和iptables
規則。此外,配置默認橋接網絡發生在Docker本身之外,並且需要重新啟動Docker。
使用創建和配置用戶定義的橋接網絡 docker network create
。如果不同的應用程序組具有不同的網絡要求,則可以在創建時單獨配置每個用戶定義的橋接網絡。
默認橋接網絡上的容器共享環境變量
-
最初,在兩個容器之間共享環境變量的唯一方法是使用
--link
標志鏈接它們。用戶定義的網絡無法實現這種類型的變量共享。但是,有更好的方法來共享環境變量。一些想法:
連接到同一用戶定義的橋接網絡的容器有效地將所有端口相互暴露。對於可以訪問不同網絡上的容器或非Docker主機的端口,必須使用or 標志發布該端口。-p
--publish
管理用戶定義的橋
使用此docker network create
命令可以創建用戶定義的橋接網絡。
$ docker network create my-net
您可以指定子網,IP地址范圍,網關和其他選項。有關詳細信息,請參閱 docker network create reference或輸出docker network create --help
。
使用此docker network rm
命令刪除用戶定義的橋接網絡。如果容器當前已連接到網絡, 請先斷開它們 。
$ docker network disconnect my-net my-nginx
$ docker network rm my-net
當您創建或刪除用戶定義的橋接網絡或從用戶定義的橋接網絡連接或斷開容器時,Docker使用特定操作系統的工具來管理底層網絡基礎結構(例如iptables
在Linux上添加或刪除橋接網絡設備或配置規則) )。這些細節應視為實施細節。讓Docker為您管理用戶定義的網絡。
將容器連接到用戶定義的橋
創建新容器時,可以指定一個或多個--network
標志。此示例將Nginx容器連接到my-net
網絡。它還將容器中的端口80發布到Docker宿主機上的端口8080,因此外部客戶端可以訪問該端口。連接到my-net
網絡的任何其他容器都可以訪問my-nginx
容器上的所有端口,反之亦然。
[root@benjamincloud ~]# docker create --name my-nginx \ > --network my-net \ > --publish 8080:80 \ > nginx:latest
要將正在運行的容器連接到現有的用戶定義的橋,請使用該 docker network connect
命令。以下命令將已在運行的my-nginx
容器連接 到已存在的my-net
網絡:
[root@benjamincloud ~]# docker network connect my-net my-nginx
斷開容器與用戶定義的橋接器的連接
要斷開正在運行的容器與用戶定義的橋接器的連接,請使用該docker network disconnect
命令。以下命令將my-nginx
容器與my-net
網絡斷開連接。
[root@benjamincloud ~]# docker network disconnect my-net my-nginx
使用IPv6
如果需要對Docker容器的IPv6支持,則需要 在創建任何IPv6網絡或分配容器IPv6地址之前,在Docker守護程序上啟用該選項並重新加載其配置。
創建網絡時,可以指定--ipv6
標志以啟用IPv6。您無法在默認bridge
網絡上有選擇地禁用IPv6支持。
啟用從Docker容器轉發到外部世界
默認情況下,來自連接到默認橋接網絡的容器的流量 不會轉發到外部世界。要啟用轉發,您需要更改兩個設置。這些不是Docker命令,它們會影響Docker主機的內核。
-
配置Linux內核以允許IP轉發。
$ sysctl net.ipv4.conf.all.forwarding=1
-
將策略的
iptables
FORWARD
策略更改DROP
為ACCEPT
。$ sudo iptables -P FORWARD ACCEPT
這些設置在重新啟動時不會持續存在,因此您可能需要將它們添加到啟動腳本中,或者相應的配置文件中。
使用默認橋接網絡
默認bridge
網絡被視為Docker的遺留細節,不建議用於生產用途。配置它是一種手動操作,它有 技術缺點。
將容器連接到默認橋接網絡
如果未使用該--network
標志指定網絡,並且指定了網絡驅動程序,則默認情況下容器將連接到默認bridge
網絡。連接到默認bridge
網絡的容器只能通過IP地址進行通信,除非它們使用舊--link
標志進行鏈接 。
配置默認橋接網絡
要配置默認bridge
網絡,請在中指定選項daemon.json
。這是一個daemon.json
指定了幾個選項的示例。僅指定您需要自定義的設置。
{ "bip": "192.168.1.5/24", "fixed-cidr": "192.168.1.5/25", "fixed-cidr-v6": "2001:db8::/64", "mtu": 1500, "default-gateway": "10.20.1.1", "default-gateway-v6": "2001:db8:abcd::89", "dns": ["10.20.1.2","10.20.1.3"] }
重新啟動Docker以使更改生效。
將IPv6與默認橋接網絡一起使用
如果將Docker配置為支持IPv6(請參閱使用IPv6),則還會自動為IPv6配置默認橋接網絡。與用戶定義的橋接網絡不同,您無法在默認橋接網絡上有選擇地禁用IPv6。
與獨立容器聯網
預計閱讀時間: 18分鍾
這一系列教程涉及獨立Docker容器的網絡連接。有關群組服務的網絡,請參閱 使用群組服務進行網絡連接。如果您需要了解有關Docker網絡的更多信息,請參閱概述。
這里僅介紹linux下的教程
-
使用默認橋接網絡演示了如何使用
bridge
Docker自動為您設置的默認網絡。該網絡不是生產系統的最佳選擇。 -
使用用戶自定的網絡顯示如何創建和使用自己的自定義橋接網絡,以連接在同一Docker主機上運行的容器。對於在生產中運行的獨立容器,建議使用此選項。
盡管覆蓋網絡通常用於群集服務,但Docker 17.06及更高版本允許您將覆蓋網絡用於獨立容器。
使用默認橋接網絡
在此示例中,您alpine
在同一個Docker主機上啟動兩個不同的容器,並進行一些測試以了解它們如何相互通信。您需要安裝並運行Docker。
1.打開終端窗口。在執行任何其他操作之前列出當前網絡。如果您從未在此Docker守護程序上添加網絡或初始化群組,那么您應該看到以下內容。您可能會看到不同的網絡,但至少應該看到這些(網絡ID會有所不同):
$ docker network ls NETWORK ID NAME DRIVER SCOPE 17e324f45964 bridge bridge local 6ed54d316334 host host local 7092879f2cc8 none null local
2.bridge是
默認網絡, 以及host
和none
。后兩者不是完全成熟的網絡,但用於啟動直接連接到Docker守護程序主機的網絡堆棧的容器,或用於啟動沒有網絡設備的容器。本教程將兩個容器連接到bridge
網絡。
啟動兩個alpine
容器運行ash
,這是Alpine的默認shell是ash而不是bash
。該-dit
標志意味着要首先分離容器(背景),互動(與輸入到它的能力),並與TTY(這樣你就可以看到輸入和輸出)。
由於您正在啟動它,因此您不會立即連接到容器。而是打印容器的ID。由於您尚未指定任何 --network
標志,因此容器將連接到默認bridge
網絡。
$ docker run -dit --name alpine1 alpine ash
$ docker run -dit --name alpine2 alpine ash
檢查兩個容器是否實際啟動:
3.檢查bridge
網絡以查看連接到它的容器。
在頂部附近,bridge
列出了有關網絡的信息,包括Docker主機和bridge
網絡之間的網關的IP地址(172.17.0.1
)。在Containers
密鑰下面,列出了每個連接的容器,以及有關其IP地址(172.17.0.2
for alpine1
和172.17.0.3
for alpine2
)的信息。
4.由於容器在后台運行。使用docker attach
命令連接到alpine1
。
[root@benjamincloud ~]# docker attach alpine1
/ #
提示符更改為#
表示您是root
容器中的用戶。使用該ip addr show
命令顯示alpine1
容器內的網絡接口:
第一個接口是環回設備。暫時忽略它。請注意,第二個接口具有IP地址172.17.0.2
,該地址alpine1
與上一步中顯示的地址相同。
5.從內部alpine1
,確保您可以通過ping連接到互聯網baidu.com
。該-c 2
標志將命令限制為兩次ping
嘗試。
6.現在嘗試ping第二個容器。首先,通過IP地址ping它 172.17.0.3
:
這成功了。接下來,嘗試alpine2
按容器名稱ping 容器。這將失敗。
alpine1
使用分離序列分離而不停止它, CTRL
+ p 然后
q
(按住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容器。
1.創建alpine-net
網絡。您不需要該--driver bridge
標志,因為它是默認值,但此示例顯示了如何指定它。
[root@benjamincloud ~]# docker network create --driver bridge alpine-net
65ddc2eff605b8efdabfb8e476af20de32b9babdd2bf12d2b3182115b03abfaf
2.列出Docker的網絡:
檢查alpine-net
網絡。這將顯示其IP地址以及沒有容器連接到它的事實:
請注意,該網絡的網關172.18.0.1
與其網關所在的默認網橋相對172.17.0.1
。您的系統上的確切IP地址可能有所不同。
3.創建您的四個容器。注意--network
標志。您只能在docker run
命令期間連接到一個網絡,因此您需要在 docker network connect
以后連接alpine4
到bridge
網絡。
[root@benjamincloud ~]# docker run -dit --name alpine1 --network alpine-net alpine ash afe579c54cf2dc7c247d2b6a2a8db98b3f7296f002a07be21aa27dd4cf8f052b [root@benjamincloud ~]# docker run -dit --name alpine2 --network alpine-net alpine ash 9a1a89cff8ea0028ea2ebb7e20b90354d4dc7475d9c716b8040e8b325cdb0f01 [root@benjamincloud ~]# docker run -dit --name alpine3 alpine ash b0c0451946a0c8929cd31da1133b812b6353a59542a00f70938f2e3b70305ef2 [root@benjamincloud ~]# docker run -dit --name alpine4 --network alpine-net alpine ash c9d91c0cf3d5d30514c649a13c772b1cefc26578b1155aaac0b79fde8c95984e
驗證所有容器是否正在運行:
4.再次檢查bridge
網絡和alpine-net
網絡:
容器alpine1
,alpine2
和alpine4
連接到 alpine-net
網絡。
5. 在用戶定義的網絡上alpine-net
,容器不僅可以通過IP地址進行通信,
還可以將容器名稱解析為IP地址。此功能稱為自動服務發現。讓我們連接alpine1
並測試一下。
alpine1
應該能夠解析 alpine2
和alpine4
(和alpine1
本身)IP地址。
/ # ping -c2 alpine1 PING alpine1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.041 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.066 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.041/0.053/0.066 ms / # ping -c2 alpine2 PING alpine2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.080 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.096 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.080/0.088/0.096 ms / # ping -c2 alpine4 PING alpine4 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.086 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.100 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.086/0.093/0.100 ms
6.從alpine1
,您根本無法連接alpine3
,因為它不在alpine-net
網絡上。
/ # ping -c2 alpine3 ping: bad address 'alpine3'
不僅如此,而且無法連接到alpine3
來自alpine1
它的IP地址的ping。回顧一下網絡的docker network inspect
輸出 bridge
並查找alpine3
IP地址:172.17.0.2
嘗試ping它。
/ # ping -c2 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+p 接q
7.請記住,alpine4
它連接到默認bridge
網絡和alpine-net
。它應該能夠到達所有其他容器。但是,您需要alpine3
通過其IP地址進行尋址。連接到它並運行測試。
/ # 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.065 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.132 ms --- alpine1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.065/0.098/0.132 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.101 ms 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.121 ms --- alpine2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.101/0.111/0.121 ms / # ping -c 2 alpine3 ping: bad address 'alpine3' / # 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.074 ms 64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.067 ms --- alpine4 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.067/0.070/0.074 ms / # 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.124 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.097 ms --- 172.17.0.2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.097/0.110/0.124 ms
8.作為最終測試,請確保您的容器都可以通過ping來連接到Internet baidu.com
。你已經附上了,alpine4
所以從那里開始嘗試。
接下來,分離alpine4
並連接alpine3
(僅連接到bridge
網絡),然后重試。最后,連接到alpine1
(僅連接到alpine-net
網絡)並再試一次。
/ # ping -c2 baidu.com PING baidu.com (220.181.57.216): 56 data bytes 64 bytes from 220.181.57.216: seq=0 ttl=50 time=57.520 ms 64 bytes from 220.181.57.216: seq=1 ttl=50 time=57.523 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 57.520/57.521/57.523 ms / # read escape sequence [root@benjamincloud ~]# docker attach alpine3 / # ping -c 2 baidu.com PING baidu.com (123.125.115.110): 56 data bytes 64 bytes from 123.125.115.110: seq=0 ttl=51 time=36.863 ms 64 bytes from 123.125.115.110: seq=1 ttl=51 time=36.954 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 36.863/36.908/36.954 ms / # read escape sequence [root@benjamincloud ~]# docker attach alpine1 / # ping -c 2 baidu.com PING baidu.com (220.181.57.216): 56 data bytes 64 bytes from 220.181.57.216: seq=0 ttl=50 time=57.521 ms 64 bytes from 220.181.57.216: seq=1 ttl=50 time=57.547 ms --- baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 57.521/57.534/57.547 ms
9.停止並刪除所有容器和alpine-net
網絡。
root@benjamincloud ~]# docker stop alpine1 alpine2 alpine3 alpine4 alpine1 alpine2 alpine3 alpine4 [root@benjamincloud ~]# docker rm alpine1 alpine2 alpine3 alpine4 alpine1 alpine2 alpine3 alpine4 [root@benjamincloud ~]# docker network rm alpine-net alpine-net