Docker 網路模式詳解及容器間網路通訊
當項目大規模使用 Docker 時,容器通訊的問題也就產生了。要解決容器通訊問題,必須先了解很多關於網路的知識。Docker 作為目前最火的輕量級容器技術,有很多令人稱道的功能,如 Docker 的鏡像管理。然而,Docker 同樣有著很多不完善的地方,網路方面就是 Docker 比較薄弱的部分。因此,我們有必要深入了解 Docker 的網路知識,以滿足更高的網路需求。
默認網路
安裝 Docker 以後,會默認創建三種網路,可以通過 docker network ls
查看。
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
688d1970f72e bridge bridge local
885da101da7d host host local
f4f1b3cf1b7f none null local
在學習 Docker 網路之前,我們有必要先來了解一下這幾種網路模式都是什麼意思。
網路模式 | 簡介 |
---|---|
bridge | 為每一個容器分配、設置 IP 等,並將容器連接到一個 docker0 虛擬網橋,默認為該模式。 |
host | 容器將不會虛擬出自己的網卡,配置自己的 IP 等,而是使用宿主機的 IP 和埠。 |
none | 容器有獨立的 Network namespace,但並沒有對其進行任何網路設置,如分配 veth pair 和網橋連接,IP 等。 |
container | 新創建的容器不會創建自己的網卡和配置自己的 IP,而是和一個指定的容器共享 IP、埠範圍等。 |
bridge 網路模式
在該模式中,Docker 守護進程創建了一個虛擬乙太網橋 docker0
,新建的容器會自動橋接到這個介面,附加在其上的任何網卡之間都能自動轉發數據包。
默認情況下,守護進程會創建一對對等虛擬設備介面 veth pair
,將其中一個介面設置為容器的 eth0
介面(容器的網卡),另一個介面放置在宿主機的命名空間中,以類似 vethxxx
這樣的名字命名,從而將宿主機上的所有容器都連接到這個內部網路上。
比如我運行一個基於 busybox
鏡像構建的容器 bbox01
,查看 ip addr
:
busybox 被稱為嵌入式 Linux 的瑞士軍刀,整合了很多小的 unix 下的通用功能到一個小的可執行文件中。
然後宿主機通過 ip addr
查看資訊如下:
通過以上的比較可以發現,證實了之前所說的:守護進程會創建一對對等虛擬設備介面 veth pair
,將其中一個介面設置為容器的 eth0
介面(容器的網卡),另一個介面放置在宿主機的命名空間中,以類似 vethxxx
這樣的名字命名。
同時,守護進程還會從網橋 docker0
的私有地址空間中分配一個 IP 地址和子網給該容器,並設置 docker0 的 IP 地址為容器的默認網關。也可以安裝 yum install -y bridge-utils
以後,通過 brctl show
命令查看網橋資訊。
對於每個容器的 IP 地址和 Gateway 資訊,我們可以通過 docker inspect 容器名稱|ID
進行查看,在 NetworkSettings
節點中可以看到詳細資訊。
我們可以通過 docker network inspect bridge
查看所有 bridge
網路模式下的容器,在 Containers
節點中可以看到容器名稱。
關於
bridge
網路模式的使用,只需要在創建容器時通過參數--net bridge
或者--network bridge
指定即可,當然這也是創建容器默認使用的網路模式,也就是說這個參數是可以省略的。
Bridge 橋接模式的實現步驟主要如下:
- Docker Daemon 利用 veth pair 技術,在宿主機上創建一對對等虛擬網路介面設備,假設為 veth0 和 veth1。而
veth pair 技術的特性可以保證無論哪一個 veth 接收到網路報文,都會將報文傳輸給另一方。 - Docker Daemon 將 veth0 附加到 Docker Daemon 創建的 docker0 網橋上。保證宿主機的網路報文可以發往 veth0;
- Docker Daemon 將 veth1 添加到 Docker Container 所屬的 namespace 下,並被改名為 eth0。如此一來,宿主機的網路報文若發往 veth0,則立即會被 Container 的 eth0 接收,實現宿主機到 Docker Container 網路的聯通性;同時,也保證 Docker Container 單獨使用 eth0,實現容器網路環境的隔離性。
host 網路模式
- host 網路模式需要在創建容器時通過參數
--net host
或者--network host
指定; - 採用 host 網路模式的 Docker Container,可以直接使用宿主機的 IP 地址與外界進行通訊,若宿主機的 eth0 是一個公有 IP,那麼容器也擁有這個公有 IP。同時容器內服務的埠也可以使用宿主機的埠,無需額外進行 NAT 轉換;
- host 網路模式可以讓容器共享宿主機網路棧,這樣的好處是外部主機與容器直接通訊,但是容器的網路缺少隔離性。
比如我基於 host
網路模式創建了一個基於 busybox
鏡像構建的容器 bbox02
,查看 ip addr
:
然後宿主機通過 ip addr
查看資訊如下:
對,你沒有看錯,返回資訊一模一樣,我也可以肯定我沒有截錯圖,不信接著往下看。我們可以通過 docker network inspect host
查看所有 host
網路模式下的容器,在 Containers
節點中可以看到容器名稱。
none 網路模式
- none 網路模式是指禁用網路功能,只有 lo 介面 local 的簡寫,代表 127.0.0.1,即 localhost 本地環回介面。在創建容器時通過參數
--net none
或者--network none
指定; - none 網路模式即不為 Docker Container 創建任何的網路環境,容器內部就只能使用 loopback 網路設備,不會再有其他的網路資源。可以說 none 模式為 Docke Container 做了極少的網路設定,但是俗話說得好「少即是多」,在沒有網路配置的情況下,作為 Docker 開發者,才能在這基礎做其他無限多可能的網路訂製開發。這也恰巧體現了 Docker 設計理念的開放。
比如我基於 none
網路模式創建了一個基於 busybox
鏡像構建的容器 bbox03
,查看 ip addr
:
我們可以通過 docker network inspect none
查看所有 none
網路模式下的容器,在 Containers
節點中可以看到容器名稱。
container 網路模式
- Container 網路模式是 Docker 中一種較為特別的網路的模式。在創建容器時通過參數
--net container:已運行的容器名稱|ID
或者--network container:已運行的容器名稱|ID
指定; - 處於這個模式下的 Docker 容器會共享一個網路棧,這樣兩個容器之間可以使用 localhost 高效快速通訊。
Container 網路模式即新創建的容器不會創建自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、埠範圍等。同樣兩個容器除了網路方面相同之外,其他的如文件系統、進程列表等還是隔離的。
比如我基於容器 bbox01
創建了 container
網路模式的容器 bbox04
,查看 ip addr
:
容器 bbox01
的 ip addr
資訊如下:
宿主機的 ip addr
資訊如下:
通過以上測試可以發現,Docker 守護進程只創建了一對對等虛擬設備介面用於連接 bbox01 容器和宿主機,而 bbox04 容器則直接使用了 bbox01 容器的網卡資訊。
這個時候如果將 bbox01 容器停止,會發現 bbox04 容器就只剩下 lo 介面了。
然後 bbox01 容器重啟以後,bbox04 容器也重啟一下,就又可以獲取到網卡資訊了。
link
docker run --link
可以用來鏈接兩個容器,使得源容器(被鏈接的容器)和接收容器(主動去鏈接的容器)之間可以互相通訊,並且接收容器可以獲取源容器的一些數據,如源容器的環境變數。
這種方式官方已不推薦使用,並且在未來版本可能會被移除,所以這裡不作為重點講解,感興趣可自行了解。
官網警告資訊://docs.docker.com/network/links/
自定義網路
雖然 Docker 提供的默認網路使用比較簡單,但是為了保證各容器中應用的安全性,在實際開發中更推薦使用自定義的網路進行容器管理,以及啟用容器名稱到 IP 地址的自動 DNS 解析。
從 Docker 1.10 版本開始,docker daemon 實現了一個內嵌的 DNS server,使容器可以直接通過容器名稱通訊。方法很簡單,只要在創建容器時使用
--name
為容器命名即可。但是使用 Docker DNS 有個限制:只能在 user-defined 網路中使用。也就是說,默認的 bridge 網路是無法使用 DNS 的,所以我們就需要自定義網路。
創建網路
通過 docker network create
命令可以創建自定義網路模式,命令提示如下:
進一步查看 docker network create
命令使用詳情,發現可以通過 --driver
指定網路模式且默認是 bridge
網路模式,提示如下:
創建一個基於 bridge
網路模式的自定義網路模式 custom_network
,完整命令如下:
docker network create custom_network
通過 docker network ls
查看網路模式:
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b3634bbd8943 bridge bridge local
062082493d3a custom_network bridge local
885da101da7d host host local
f4f1b3cf1b7f none null local
通過自定義網路模式 custom_network
創建容器:
docker run -di --name bbox05 --net custom_network busybox
通過 docker inspect 容器名稱|ID
查看容器的網路資訊,在 NetworkSettings
節點中可以看到詳細資訊。
連接網路
通過 docker network connect 網路名稱 容器名稱
為容器連接新的網路模式。
docker network connect bridge bbox05
通過 docker inspect 容器名稱|ID
再次查看容器的網路資訊,多增加了默認的 bridge
。
斷開網路
通過 docker network disconnect 網路名稱 容器名稱
命令斷開網路。
docker network disconnect custom_network bbox05
通過 docker inspect 容器名稱|ID
再次查看容器的網路資訊,發現只剩下默認的 bridge
。
移除網路
可以通過 docker network rm 網路名稱
命令移除自定義網路模式,網路模式移除成功會返回網路模式名稱。
docker network rm custom_network
注意:如果通過某個自定義網路模式創建了容器,則該網路模式無法刪除。
容器間網路通訊
接下來我們通過所學的知識實現容器間的網路通訊。首先明確一點,容器之間要互相通訊,必須要有屬於同一個網路的網卡。
我們先創建兩個基於默認的 bridge
網路模式的容器。
docker run -di --name default_bbox01 busybox
docker run -di --name default_bbox02 busybox
通過 docker network inspect bridge
查看兩容器的具體 IP 資訊。
然後測試兩容器間是否可以進行網路通訊。
經過測試,從結果得知兩個屬於同一個網路的容器是可以進行網路通訊的,但是 IP 地址可能是不固定的,有被更改的情況發生,那容器內所有通訊的 IP 地址也需要進行更改,能否使用容器名稱進行網路通訊?繼續測試。
經過測試,從結果得知使用容器進行網路通訊是不行的,那怎麼實現這個功能呢?
從 Docker 1.10 版本開始,docker daemon 實現了一個內嵌的 DNS server,使容器可以直接通過容器名稱通訊。方法很簡單,只要在創建容器時使用 --name
為容器命名即可。
但是使用 Docker DNS 有個限制:只能在 user-defined 網路中使用。也就是說,默認的 bridge 網路是無法使用 DNS 的,所以我們就需要自定義網路。
我們先基於 bridge
網路模式創建自定義網路 custom_network
,然後創建兩個基於自定義網路模式的容器。
docker run -di --name custom_bbox01 --net custom_network busybox
docker run -di --name custom_bbox02 --net custom_network busybox
通過 docker network inspect custom_network
查看兩容器的具體 IP 資訊。
然後測試兩容器間是否可以進行網路通訊,分別使用具體 IP 和容器名稱進行網路通訊。
經過測試,從結果得知兩個屬於同一個自定義網路的容器是可以進行網路通訊的,並且可以使用容器名稱進行網路通訊。
那如果此時我希望 bridge
網路下的容器可以和 custom_network
網路下的容器進行網路又該如何操作?其實答案也非常簡單:讓 bridge
網路下的容器連接至新的 custom_network
網路即可。
docker network connect custom_network default_bbox01
學完容器網路通訊,大家就可以練習使用多個容器完成常見應用集群的部署了。後面就該學習 Docker 進階部分的內容 Docker Compose 和 Docker Swarm。
本文採用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議
。
🤗 您的點贊
和轉發
是對我最大的支援。
📢 掃碼關注 哈嘍沃德先生
「文檔 + 影片」每篇文章都配有專門影片講解,學習更輕鬆噢 ~