跳轉到

任務六:容器網路

開始之前

任務目標

在這個任務中,你將學習:

  • 理解 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 網路啟動容器
docker run -d --name web nginx

# 檢查容器的網路設定
docker inspect web | grep IPAddress

預設 bridge 的限制

預設 bridge 網路不支援容器名稱解析。如果你需要用容器名稱互相存取,請使用自訂 bridge 網路。

Host 模式

Host 模式讓容器直接使用 Host 的網路堆疊,不建立獨立的網路命名空間。

運作原理:

  • 容器與 Host 共享網路
  • 容器內的應用直接監聽 Host 的網路介面
  • 不需要 port mapping,效能最佳

適用場景:

  • 需要最佳網路效能的應用
  • 需要存取 Host 網路介面的應用

範例:

# 使用 host 網路模式
docker run -d --network host --name web nginx

Host 模式的平台限制

在 macOS 和 Windows 上,Docker 實際上執行在虛擬機內,因此 --network host 模式的行為與 Linux 不同。容器會使用虛擬機的網路,而非真正的 Host 網路。

在這些平台上,你可能無法像在 Linux 上一樣直接存取 Host 的網路介面。

None 模式

None 模式完全隔離容器的網路,容器沒有任何網路連接。

運作原理:

  • 容器只有 loopback(lo)介面
  • 無法與外部網路或其他容器通訊

適用場景:

  • 需要完全網路隔離的安全容器
  • 手動設定自訂網路的基礎容器

範例:

# 使用 none 網路模式
docker run -d --network none --name isolated busybox sleep 3600

自訂 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)會自動解析同網路內的容器名稱。

運作原理:

  1. 容器 A 嘗試存取 container-b
  2. 請求發送到 Docker DNS 伺服器
  3. DNS 伺服器查詢 container-b 的 IP 位址
  4. 返回 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 為容器設定網路別名:

docker run -d \
    --name postgres \
    --network app-network \
    --network-alias database \
    postgres:18

現在其他容器可以使用 databasepostgres 存取這個容器。

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

同時對應多個埠號:

docker run -d \
    -p 8080:80 \
    -p 8443:443 \
    nginx

範圍 Port Mapping

對應一段連續的埠號:

# 對應 8000-8010 到容器的 8000-8010
docker run -d -p 8000-8010:8000-8010 myapp

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 psnetstat/lsof 檢查埠號使用狀況。

# 檢查埠號是否被佔用(macOS/Linux)
lsof -i :8080
netstat -tuln | grep 8080

實用範例

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 ls

檢查網路詳細資訊

# 查看網路的設定與連接的容器
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

# 列出容器的所有 port mapping
docker port <container-name>

容器內部除錯

有時需要進入容器內部進行網路除錯:

測試網路連線

# 使用 ping 測試連線
docker exec <container-name> ping -c 4 google.com

# 測試容器間連線
docker exec web ping db

測試 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 解析

# 測試 DNS 解析
docker exec <container-name> nslookup db

# 或使用 dig
docker exec <container-name> dig db

檢查網路介面

# 列出網路介面
docker exec <container-name> ip addr

# 檢查路由表
docker exec <container-name> ip route

工具可用性

並非所有容器映像都包含網路除錯工具(如 pingcurlnc)。輕量級映像(如 Alpine、Distroless)通常不包含這些工具。

如果需要除錯,可以:

  1. 臨時安裝工具(如 apk add curl
  2. 使用包含完整工具的基礎映像進行測試
  3. 使用 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:建立自訂網路

docker network create webapp-network

步驟 2:啟動資料庫容器

docker run -d \
    --name db \
    --network webapp-network \
    -e POSTGRES_PASSWORD=mysecret \
    -e POSTGRES_DB=myapp \
    postgres:18

為什麼不設定 port mapping?

資料庫容器不需要對外開放,只需要讓同網路的其他容器存取即可。這樣可以提高安全性。

步驟 3:啟動 Web 伺服器容器

docker run -d \
    --name web \
    --network webapp-network \
    -p 8080:80 \
    nginx

步驟 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 stop web db
docker rm web db

# 移除網路
docker network rm webapp-network

練習延伸

建立多層網路架構

# 建立前端網路
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 網路的核心概念,能夠為容器建立適合的網路架構、設定容器間通訊,並使用各種工具進行網路除錯。在實際專案中,良好的網路架構是建構可靠、安全的容器化應用的基礎!