從一個簡單的問題開始#

兩個 Container 跑在同一台主機上,它們要怎麼互相連線?再進一步,它們又要怎麼跟外網通訊?

要回答這個問題,得先認識 Docker Network(Docker 網路)的幾種驅動模式。Docker 用 Linux 的 Network Namespace(網路命名空間)把每個容器隔離起來,再透過不同的 driver 決定「隔離到什麼程度」、「怎麼跟外界連起來」。

Docker 提供的網路驅動#

執行 docker network ls 可以看到預設提供的幾種 driver:

docker network ls

常見的有以下幾種:

  • none
  • host
  • bridge
  • container
  • overlay

每一種背後對應的隔離程度與使用情境都不同。

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