任務六:容器網路¶
開始之前¶
任務目標
在這個任務中,你將學習:
- 理解 Docker 的四種網路模式(bridge、host、none、自訂 bridge)
- 掌握容器間通訊與內建 DNS 機制
- 學會使用 port mapping 將容器服務對外開放
- 熟悉網路檢查與除錯技巧
- 透過實作練習建立自訂網路並連接多個容器
Docker 網路模式¶
Docker 提供多種網路模式,讓容器能以不同方式與外部網路、Host 以及其他容器通訊。理解這些模式的差異,能幫助你為應用程式選擇最適合的網路架構。
Bridge 模式(預設)¶
Bridge 是 Docker 的預設網路模式。當你啟動容器時,Docker 會自動將容器連接到名為 bridge 的預設網路。
運作原理:
- Docker 在 Host 上建立虛擬網橋(docker0)
- 每個容器獲得獨立的 IP 位址
- 容器透過 NAT(Network Address Translation)與外部網路通訊
- 容器之間可透過 IP 位址互相存取
適用場景:
- 一般的單 Host 應用部署
- 不需要與 Host 網路直接互動的應用
範例:
預設 bridge 的限制
預設 bridge 網路不支援容器名稱解析。如果你需要用容器名稱互相存取,請使用自訂 bridge 網路。
Host 模式¶
Host 模式讓容器直接使用 Host 的網路堆疊,不建立獨立的網路命名空間。
運作原理:
- 容器與 Host 共享網路
- 容器內的應用直接監聽 Host 的網路介面
- 不需要 port mapping,效能最佳
適用場景:
- 需要最佳網路效能的應用
- 需要存取 Host 網路介面的應用
範例:
Host 模式的平台限制
在 macOS 和 Windows 上,Docker 實際上執行在虛擬機內,因此 --network host 模式的行為與 Linux 不同。容器會使用虛擬機的網路,而非真正的 Host 網路。
在這些平台上,你可能無法像在 Linux 上一樣直接存取 Host 的網路介面。
None 模式¶
None 模式完全隔離容器的網路,容器沒有任何網路連接。
運作原理:
- 容器只有 loopback(lo)介面
- 無法與外部網路或其他容器通訊
適用場景:
- 需要完全網路隔離的安全容器
- 手動設定自訂網路的基礎容器
範例:
自訂 Bridge 網路(推薦)¶
自訂 bridge 網路提供比預設 bridge 更多的功能與控制。
優點:
- 內建 DNS 解析:容器可透過容器名稱互相存取
- 更好的隔離性:不同自訂網路的容器預設無法互相通訊
- 可動態連接/斷開:容器可在執行時加入或離開網路
- 可設定網路參數:子網路、閘道、MTU 等
建立自訂網路:
# 建立自訂 bridge 網路
docker network create my-network
# 指定子網路和閘道
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-custom-network
使用自訂網路:
# 啟動容器時指定網路
docker run -d --name web --network my-network nginx
# 動態將容器加入網路
docker network connect my-network existing-container
# 從網路移除容器
docker network disconnect my-network existing-container
最佳實務
在生產環境中,建議為不同的應用建立專屬的自訂網路,以實現更好的網路隔離與管理。
容器間通訊與內建 DNS¶
在同一個自訂 bridge 網路中,Docker 提供內建的 DNS 服務,讓容器可透過容器名稱互相存取。
內建 DNS 機制¶
Docker 的內建 DNS 伺服器(監聽在 127.0.0.11)會自動解析同網路內的容器名稱。
運作原理:
- 容器 A 嘗試存取
container-b - 請求發送到 Docker DNS 伺服器
- DNS 伺服器查詢
container-b的 IP 位址 - 返回 IP 位址,完成連線
範例:
# 建立自訂網路
docker network create app-network
# 啟動資料庫容器
docker run -d \
--name db \
--network app-network \
-e POSTGRES_PASSWORD=secret \
postgres:18
# 啟動應用容器(可透過 'db' 存取資料庫)
docker run -d \
--name app \
--network app-network \
-e DATABASE_HOST=db \
-e DATABASE_PORT=5432 \
myapp:latest
在這個範例中,app 容器可以使用 db:5432 連接到資料庫,無需知道資料庫的 IP 位址。
測試容器間連線¶
你可以使用各種工具測試容器間的連線:
# 使用 ping 測試(需要容器映像包含 ping 工具)
docker exec app ping db
# 使用 curl 測試 HTTP 連線
docker exec app curl http://web:80
# 使用 nc 測試 port 連線
docker exec app nc -zv db 5432
容器名稱別名
你可以使用 --network-alias 為容器設定網路別名:
現在其他容器可以使用 database 或 postgres 存取這個容器。
Port Mapping 詳解¶
Port mapping(埠號對應)讓你將容器內的服務埠號對應到 Host 的埠號,使外部網路可以存取容器服務。
基本語法¶
使用 -p 或 --publish 參數設定 port mapping:
# 基本格式:-p <host-port>:<container-port>
docker run -d -p 8080:80 nginx
# 完整格式:-p <host-ip>:<host-port>:<container-port>
docker run -d -p 127.0.0.1:8080:80 nginx
參數說明:
host-port:Host 上的埠號container-port:容器內的埠號host-ip(可選):Host 上要綁定的 IP 位址
進階用法¶
隨機分配 Host 埠號¶
讓 Docker 自動分配可用的 Host 埠號:
# 使用 -P(大寫)或 -p 不指定 host port
docker run -d -P nginx
docker run -d -p 80 nginx
# 查詢實際分配的埠號
docker port <container-name>
指定 IP 綁定¶
只在特定 IP 位址上監聽:
# 只在 localhost 監聽(外部無法存取)
docker run -d -p 127.0.0.1:8080:80 nginx
# 在特定 IP 監聽
docker run -d -p 192.168.1.100:8080:80 nginx
多個 Port Mapping¶
同時對應多個埠號:
範圍 Port Mapping¶
對應一段連續的埠號:
UDP Port Mapping¶
預設為 TCP,可明確指定 UDP:
# TCP(預設)
docker run -d -p 53:53 mydns
# UDP
docker run -d -p 53:53/udp mydns
# 同時對應 TCP 和 UDP
docker run -d -p 53:53/tcp -p 53:53/udp mydns
埠號衝突
如果 Host 上的埠號已被佔用,容器啟動會失敗。你可以使用 docker ps 或 netstat/lsof 檢查埠號使用狀況。
實用範例¶
Web 應用 + 資料庫:
# 資料庫(不對外開放)
docker run -d \
--name db \
--network app-network \
-e POSTGRES_PASSWORD=secret \
postgres:18
# Web 應用(對外開放 port 8080)
docker run -d \
--name web \
--network app-network \
-p 8080:80 \
-e DATABASE_HOST=db \
nginx
在這個範例中:
- 資料庫容器沒有設定 port mapping,只能被同網路的容器存取
- Web 應用對外開放 port 8080,外部可透過
http://localhost:8080存取
網路檢查與除錯技巧¶
當容器的網路出現問題時,以下工具與技巧能幫助你快速定位問題。
網路檢查命令¶
列出所有網路¶
檢查網路詳細資訊¶
# 查看網路的設定與連接的容器
docker network inspect bridge
# 以 JSON 格式輸出(便於處理)
docker network inspect --format='{{json .}}' my-network | jq
查詢容器的網路設定¶
# 查看容器的網路設定
docker inspect <container-name> | grep -A 20 NetworkSettings
# 只顯示 IP 位址
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container-name>
查詢 Port Mapping¶
容器內部除錯¶
有時需要進入容器內部進行網路除錯:
測試網路連線¶
測試 HTTP 服務¶
# 使用 curl 測試
docker exec <container-name> curl http://web:80
# 檢查 HTTP 回應標頭
docker exec <container-name> curl -I http://web:80
檢查 Port 是否開放¶
# 使用 nc(netcat)測試 port
docker exec <container-name> nc -zv db 5432
# 如果容器沒有 nc,可用 telnet
docker exec <container-name> telnet db 5432
檢查 DNS 解析¶
檢查網路介面¶
工具可用性
並非所有容器映像都包含網路除錯工具(如 ping、curl、nc)。輕量級映像(如 Alpine、Distroless)通常不包含這些工具。
如果需要除錯,可以:
- 臨時安裝工具(如
apk add curl) - 使用包含完整工具的基礎映像進行測試
- 使用
docker run啟動除錯容器並連接到同一網路
常見問題與解決方案¶
問題 1:容器無法互相連線
- 檢查容器是否在同一個網路:
docker network inspect <network-name> - 檢查容器名稱是否正確(拼字需一致)
- 檢查防火牆規則
問題 2:無法從 Host 存取容器服務
- 檢查 port mapping 設定:
docker port <container-name> - 確認容器內的服務正在監聽正確的埠號
- 檢查防火牆是否阻擋連線
問題 3:預設 bridge 網路中容器名稱無法解析
- 預設 bridge 不支援 DNS 解析,請使用自訂 bridge 網路
實作練習:建立自訂網路並連接多個容器¶
現在讓我們透過實作練習,建立一個完整的應用網路架構,包含 Web 應用與資料庫。
練習目標¶
建立一個包含以下元件的網路架構:
- 一個自訂 bridge 網路
- 一個 PostgreSQL 資料庫容器(不對外開放)
- 一個 Nginx Web 伺服器(對外開放 port 8080)
- 驗證容器間可以透過容器名稱互相存取
步驟說明¶
步驟 1:建立自訂網路
步驟 2:啟動資料庫容器
docker run -d \
--name db \
--network webapp-network \
-e POSTGRES_PASSWORD=mysecret \
-e POSTGRES_DB=myapp \
postgres:18
為什麼不設定 port mapping?
資料庫容器不需要對外開放,只需要讓同網路的其他容器存取即可。這樣可以提高安全性。
步驟 3:啟動 Web 伺服器容器
步驟 4:驗證網路設定
# 檢查網路詳細資訊
docker network inspect webapp-network
# 查看容器的 IP 位址
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
步驟 5:測試容器間連線
docker exec web bash -c 'apt-get update && apt-get install -y iputils-ping netcat-openbsd'
# 從 web 容器 ping 資料庫容器
docker exec web ping -c 4 db
# 測試資料庫連線(需要 psql 工具)
docker exec web nc -zv db 5432
步驟 6:從 Host 存取 Web 服務
開啟瀏覽器訪問 http://localhost:8080,應該會看到 Nginx 的歡迎頁面。
步驟 7:清理資源
練習延伸¶
建立多層網路架構¶
# 建立前端網路
docker network create frontend-network
# 建立後端網路
docker network create backend-network
# 資料庫只連接後端網路
docker run -d \
--name db \
--network backend-network \
-e POSTGRES_PASSWORD=secret \
postgres:18
# API 伺服器連接前端與後端網路
docker run -d \
--name api \
--network backend-network \
myapi:latest
docker network connect frontend-network api
# Web 伺服器只連接前端網路
docker run -d \
--name web \
--network frontend-network \
-p 8080:80 \
nginx
在這個架構中:
- Web 伺服器只能存取 API 伺服器
- API 伺服器可以存取資料庫
- Web 伺服器無法直接存取資料庫(提高安全性)
使用網路別名¶
# 為容器設定多個網路別名
docker run -d \
--name postgres \
--network webapp-network \
--network-alias database \
--network-alias db \
--network-alias postgres-server \
postgres:18
# 現在其他容器可以使用任一別名存取
docker exec web ping database
docker exec web ping db
docker exec web ping postgres-server
任務結束¶
完成!
恭喜你完成了這個任務!現在你已經學會:
- 理解 Docker 的四種網路模式(bridge、host、none、自訂 bridge)
- 掌握容器間通訊與內建 DNS 機制
- 學會使用 port mapping 將容器服務對外開放
- 熟悉網路檢查與除錯技巧
- 透過實作練習建立自訂網路並連接多個容器
你現在已經掌握 Docker 網路的核心概念,能夠為容器建立適合的網路架構、設定容器間通訊,並使用各種工具進行網路除錯。在實際專案中,良好的網路架構是建構可靠、安全的容器化應用的基礎!