本文是《Docker必知必會系列》第四篇,原文發布于個人博客:悟塵紀。
Docker 網絡配置
Docker 網絡基本原理
要實現網絡通信,機器需要至少一個網絡接口(物理接口或虛擬接口)來收發數據包。如果不同子網之間要進行通信,需要路由機制。
Docker 中的網絡接口默認都是虛擬接口,虛擬接口的優勢之一是轉發效率較高。 Linux 通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,發送接口的發送緩存中的數據包被直接復制到接收接口的接收緩存中。
當 Docker 啟動時,會自動在主機上創建一個 docker0
虛擬網橋( Linux 的一個 bridge),它會在掛載到它的網口之間進行轉發。同時,Docker 隨機分配一個本地未占用的私有網段中的一個地址給 docker0
接口,此后啟動的容器內的網口也會自動分配一個同一網段(172.17.0.0/16
)的地址。
當創建一個 Docker 容器的時候,同時會創建了一對 veth pair
接口(當數據包發送到一個接口時,另外一個接口也可以收到相同的數據包)。這對接口一端在容器內,即 eth0
;另一端在本地并被掛載到 docker0
網橋,名稱以 veth
開頭(例如 vethAQI2QT
)。通過這種方式,主機可以跟容器通信,容器之間也可以相互通信。
關于 Docker 網絡的更多內容,可以訪問:https://docs.docker.com/network/>
Docker 網絡類型
Docker 創建一個容器的時候,會執行如下操作:
- 創建一對虛擬接口,分別放到本地主機和新容器中;
- 本地主機一端橋接到默認的 docker0 或指定網橋上,并具有一個唯一的名字,如 veth65f9;
- 容器一端放到新容器中,并修改名字作為 eth0,這個接口只在容器的命名空間可見;
- 從網橋可用地址段中獲取一個空閑地址分配給容器的 eth0,并配置默認路由到橋接網卡 veth65f9。
完成這些之后,容器就可以使用 eth0 虛擬網卡來連接其他容器和其他網絡。
可以在 docker run
的時候通過 --net
參數來指定容器的網絡配置,有 4 個可選值:
-
--net=bridge
這個是默認值,連接到默認的網橋。 -
--net=host
告訴 Docker 不要將容器網絡放到隔離的命名空間中,即不要容器化容器內的網絡。此時容器使用本地主機的網絡,它擁有完全的本地主機接口訪問權限。容器進程可以跟主機其它 root 進程一樣可以打開低范圍的端口,可以訪問本地網絡服務比如 D-bus,還可以讓容器做一些影響整個主機系統的事情,比如重啟主機。因此使用這個選項的時候要非常小心。如果進一步的使用--privileged=true
,容器會被允許直接配置主機的網絡堆棧。 -
--net=container:NAME_or_ID
讓 Docker 將新建容器的進程放到一個已存在容器的網絡棧中,新容器進程有自己的文件系統、進程列表和資源限制,但會和已存在的容器共享 IP 地址和端口等網絡資源,兩者進程可以直接通過lo
環回接口通信。 -
--net=none
讓 Docker 將新容器放到隔離的網絡棧中,但是不進行網絡配置。之后,用戶可以自己進行配置。
外部訪問容器
默認情況下,容器可以主動訪問到外部網絡的連接,但是外部網絡無法訪問到容器。想要允許外部訪問容器,可以在 docker run
時候通過 -p
或 -P
參數來啟用(可以多次使用 -p
標記來綁定多個端口)。
使用 docker ps
可以看到,本地主機的 80 被映射到了容器的 80
端口。此時訪問本機的 80
端口即可訪問容器內 nginx
應用提供的界面。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 nginx "nginx -g '…" 5 days ago Up 4 days 0.0.0.0:80->80/tcp nginx
容器間互聯
先創建一個新的 Docker 網絡:
docker network create -d bridge lixl-net
-
-d
參數指定 Docker 網絡類型,有bridge
,overlay
。其中overlay
網絡類型用于 Swarm mode。
運行一個容器并連接到新建的 lixl-net
網絡
docker run -it --rm --name busybox1 --network lixl-net busybox sh
打開新的終端,再運行一個容器并加入到 lixl-net
網絡
docker run -it --rm --name busybox2 --network lixl-net busybox sh
再打開一個新的終端查看容器信息
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b47060aca56b busybox "sh" 1 minutes ago Up 1 minutes busybox2
8720575823ec busybox "sh" 1 minutes ago Up 1 minutes busybox1
下面通過 ping
來證明 busybox1
容器和 busybox2
容器建立了互聯關系。
在 busybox1
容器輸入以下命令
/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
用 ping 來測試連接 busybox2
容器,它會解析成 172.19.0.3
。
同理在 busybox2
容器執行 ping busybox1
,也會成功連接到。
/ # ping busybox1
PING busybox1 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
這樣,busybox1
容器和 busybox2
容器建立了互聯關系。
如果有多個容器之間需要互相連接,推薦使用 Docker Compose。