從一個簡單的問題開始#
兩個 Container 跑在同一台主機上,它們要怎麼互相連線?再進一步,它們又要怎麼跟外網通訊?
要回答這個問題,得先認識 Docker Network(Docker 網路)的幾種驅動模式。Docker 用 Linux 的 Network Namespace(網路命名空間)把每個容器隔離起來,再透過不同的 driver 決定「隔離到什麼程度」、「怎麼跟外界連起來」。
Docker 提供的網路驅動#
執行 docker network ls 可以看到預設提供的幾種 driver:
docker network ls常見的有以下幾種:
nonehostbridgecontaineroverlay
每一種背後對應的隔離程度與使用情境都不同。
none:完全隔離#
none driver 表示容器擁有獨立的 Network Namespace,但裡面只有一個 Loopback(迴環介面)lo,沒有任何對外介面。
- 隔離程度:最高
- 對外連線能力:無
- 用途:純運算、批次任務、不需要網路的安全沙箱
docker run --rm --network none alpine ip addr預期只會看到 lo 一張介面。
host:共享主機網路#
host driver 直接把容器塞進主機的 Network Namespace,沒有自己的網路堆疊。
- 隔離程度:最低(網路層完全不隔離)
- 對外連線能力:與主機相同
- 用途:對網路效能敏感的服務、需要綁多個 port 的代理
host 模式下容器看到的網路介面與主機完全一致,port 衝突風險也來自主機自身。
bridge:預設模式#
bridge driver 是 Docker 預設使用的模式。它會建立一個 Linux bridge(名稱通常是 docker0),每個容器透過一對 veth pair(虛擬乙太網對)接到這座 bridge 上。
- 隔離程度:中等(容器有自己的 namespace,透過 bridge 互通)
- 對外連線能力:靠 iptables 的 NAT(Network Address Translation)規則出網
- 用途:絕大多數單機容器情境
docker network inspect bridge後面的章節會花最多篇幅在這個模式上,因為它把 veth pair、bridge、iptables、ip_forward 等核心概念全部串起來。
container:共用另一個容器的網路#
container:<name> driver 表示「跟某個既存容器共用同一個 Network Namespace」。
- 隔離程度:兩個容器共享同一個網路堆疊
- 對外連線能力:跟被共用的那個容器一致
- 用途:sidecar 模式、debug 工具容器
docker run --rm --network container:web alpine ip addr兩個容器看到的介面、IP、port 都會一模一樣。
overlay:跨主機網路#
overlay driver 是給 Swarm 或多主機叢集用的,把不同主機上的容器接進同一個 L2 網段,底層走 VXLAN 封裝。
- 隔離程度:每個 overlay 網路是獨立 namespace
- 對外連線能力:跨主機透通
- 用途:多節點叢集;Kubernetes 環境通常改用 CNI(Container Network Interface)外掛來達成類似效果
隔離程度速查#
由強到弱大致是:
none:什麼都沒有bridge/overlay:獨立 namespace + 受控的對外通道container:與指定容器共享host:完全不隔離
接下來要拆解什麼#
之後幾章會把 bridge 模式從零組起來:
- 用 veth pair 把兩個 namespace 接起來
- 用 Linux bridge 把多個 namespace 串成一個小區網
- 用 routing table 與 default gateway 讓容器看得到外部
- 用 iptables 的 NAT 與 FORWARD chain 讓容器真的能出網
- 最後再用 DNAT 跟 port publishing 讓外部連得回容器
延伸閱讀#
docker network ls/docker network inspect- Linux Network Namespace 文件
man 8 ip-netns