當項目大規模使用 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
可以用來鏈接兩個容器,使得源容器(被鏈接的容器)和接收容器(主動去鏈接的容器)之間可以互相通信,並且接收容器可以獲取源容器的一些數據,如源容器的環境變量。
這種方式官方已不推薦使用,並且在未來版本可能會被移除,所以這里不作為重點講解,感興趣可自行了解。
官網警告信息:https://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 國際」許可協議
。
🤗 您的點贊
和轉發
是對我最大的支持。
📢 掃碼關注 哈嘍沃德先生
「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕松噢 ~