Docker Network 網路

在 Docker 的世界中,容器不僅是獨立的,它們通常需要相互通訊(例如:Web Server 連接資料庫)或者與外界連網。Docker 提供了一套強大的網路子系統,讓開發者能以虛擬的方式管理這些通訊路徑。

本章將帶你掌握 Docker 網路的核心驅動程式與實戰技巧。

核心網路驅動程式

Docker 使用驅動程式來處理網路通訊。了解不同驅動程式的適用場景是優化架構的第一步:

  • Bridge (橋接模式)
    • 用途:預設模式,適用於單一主機上的容器通訊。
    • 特性:容器透過虛擬網橋 docker0 取得內網 IP。
  • Host (主機模式)
    • 用途:追求極致效能的應用(如高效能 Web Server)。
    • 特性:容器直接使用主機的網路棧,PORT 不需要對應,效率最高,但缺乏隔離。
  • Overlay (覆蓋網路)
    • 用途:多主機通訊、Docker Swarm 或集群架構。
    • 特性:在多台實體機之間建立一個虛擬隧道,讓不同主機上的容器像在同一個區域網路。
  • Macvlan
    • 用途:需要讓容器擁有實體網路身分(MAC 位址)的情境。
    • 特性:容器會直接連接到實體網路,適合處理舊有系統與實體機之間的通訊。
  • None
    • 用途:高安全性、不需要聯網的運算工作。
    • 特性:完全停用網路棧。

為何要自定義網路:服務發現 (Service Discovery)

Docker 內建了一套 DNS 服務。當容器加入自定義網路後,它們可以透過「容器名稱」或「網路別名」來互相通訊,這稱為服務發現。

服務發現的關鍵機制

  • 自動解析:Docker 會自動維護一套內部 DNS,將 db 這個名稱轉化為目前的 IP。容器即便重啟導致 IP 改變,名稱通訊依然有效。
  • 預設 Bridge vs. 自定義網路
    • 在「預設 bridge」中:不支援 DNS 解析,必須手動查 IP 或使用 --link(已過時)。
    • 在「自定義網路」中:原生支援 DNS 解析,這是現代 Docker 部署的標準做法。

推薦做法:為每個專案建立獨立的 Bridge 網路。

現在,你的 Web 容器可以直接透過 http://db 訪問資料庫。

進階實戰:多重網路與安全隔離

在生產環境中,我們常讓一個容器(如 Nginx 反向代理)連接多個網路,以求達到「外網接入」與「內網資料隔離」。

# 1. 建立前端網路 (對應外部來源) 與 後端網路 (內部資料庫)
docker network create frontend-net
docker network create backend-net

# 2. 資料庫只加入 backend-net (隔離,外部無法存取)
docker run -d --name mysql --network backend-net -e MYSQL_ROOT_PASSWORD=pw mysql:8.0

# 3. Nginx 同時接上兩個網路
docker run -d --name proxy --network frontend-net -p 80:80 nginx
docker network connect backend-net proxy

這樣一來,proxy 容器既能接收外部請求,也能連到 mysql;但 mysql 由於不在 frontend-net 裡,壞人就算突破了 proxy 也很難直接摸到它。

外部訪問:埠號映射 (Port Mapping)

當我們想從本機瀏覽器連到容器時,必須使用 -p 參數:

docker run -p [主機埠號]:[容器埠號] nginx
  • -p 80:80:將主機的 80 對應到容器 80。
  • -p 127.0.0.1:8080:80:只允許本地存取該容器。
  • -P (大寫):自動隨機分配主機的高位埠號到容器定義的 Exposed 埠。

Host 模式:追求極致效能的網路選擇

在某些對性能極度要求的場景中,你可能不希望網路封包經過 Docker 的虛擬層轉換,這時 host 模式就是最佳選擇。

Host 模式的運作原理

當容器使用 Host 模式啟動時,它不會獲得獨立的 IP 位址。相反地,它會直接共用宿主機的網路卡、IP 以及埠號資源。這意味著:

  • 無效能損耗:省去了 Docker 網橋與 NAT (網路地址轉換) 的處理負擔。
  • 埠號衝突:如果容器監聽 80 埠,宿主機的 80 埠就會被占走。你不能同時啟動兩個在 Host 模式下都監聽 80 埠的容器。

指令用法:--network host

使用 --network host 參數即可啟動:

# 啟動一個 Nginx 容器並使用主機網路
docker run -d --name my-host-nginx --network host nginx
在 Host 模式下,-p 參數會被完全忽略。因為容器就是宿主機,不需要做埠號對應。

什麼時候該用 Host 模式?

  • 追求極致效能:例如負載平衡器、資料庫的核心組件。
  • 網路診斷工具:當你需要容器內的程式能直接讀取宿主機網路流量。
  • 簡化通訊:當你不需要網路隔離,且希望容器服務能直接被內網存取。

安全警告:Host 模式的風險

這是一個強大但也危險的模式:

  • 缺乏隔離:容器內的惡意程式碼可能更容易存取宿主機內私有的網路服務(如僅監聽 127.0.0.1 的本地資料庫)。
  • 缺乏命名空間保護:容器可以對宿主機的網路配置(如修改 Hostname)產生影響。

管理網路的常用指令

查看網路列表

docker network ls

查看特定網路詳細資訊 (查看有哪些容器在裡面)

docker network inspect my-app-net

將運作中的容器連接到新網路

docker network connect my-app-net old-container

斷開連線

docker network disconnect my-app-net old-container

進階:Docker v29 與 nftables

Docker v29 中,引入了對 nftables 的實驗性支援。

傳統上 Docker 使用 iptables 來管理 Linux 的核心防火牆規則,但許多現代 Linux 發行版(如 Debian 11+, RHEL 9+)已經轉向效能更好的 nftables。這項更新讓 Docker 在現代 Linux 主機上的網路管理更穩定且更具前瞻性。

如果你想測試這項功能,可以在 daemon.json 中配置:

{
  "ip6tables": true,
  "experimental": true
}

檢視容器在網路中的真正狀態

如果你想看某個容器目前被分配到什麼 IP,除了 inspect 網路以外,也可以針對容器使用:

# 快速過濾出容器的 IP 位址
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [容器名稱]

清理沒在用的網路

隨著開發時間變久,會殘留許多沒在用的自定義網路,使用以下指令一鍵清理:

docker network prune

總結與最佳實踐

  • 優先使用自定義 Bridge:除了確保 DNS 自動解析,還能提供專屬該應用的網路隔離。
  • 依賴名稱而非 IP:永遠透過容器名稱(或 --network-alias)來通訊。
  • 最小化埠號暴露:只有需要對外公開的服務(如 Web 前端)才使用 -p,內部的資料庫通訊應隱藏在網路內。
  • 考慮網路效能:高性能場景首選 host,跨主機場景首選 overlay,一般應用首選 bridge