Vinc3nt's Life

從 Linux 基礎實現 Docker Bridge 網路:一步步理解容器通訊 (6)

2025-01-14
develop
linux
docker
bridge
container
iptable
nat
最後更新:2025-01-26
22分鐘
4221字

在上一章中,我們認識了 Docker 對 iptables 的修改,成功讓容器之間以及容器與外網的流量順利傳輸。然而,還有一個重要的情境需要解決:外部網路如何存取容器

經常使用 Docker 的朋友可能已經知道答案了 - Docker Container 可以透過 Port Forwarding 來實現此功能。雖然它看起來像是一項新技術,但本質上也是 Network Address Translation (NAT) 的一種實現方式。

深入研究 NAT:認識常見的 NAT 型態

在深入討論之前,讓我們先來了解 NAT 的類型。在 iptables 中,可以靈活地進行各種 Network Address Translation (NAT) 操作,主要分為兩種:Source NAT (SNAT)Destination NAT (DNAT)

SNAT:Source Network Address Translation

SNAT 會改寫封包的來源 IP 位址,讓外部看到的「Source IP」已被替換。舉個例子,當多台 PC 透過一台 ADSL Router 共享上網時,每台 PC 都配置了 Private IP。當這些 PC 連線至外部網路時,Router 會將 packet header 裡的 Source IP 改成 Router 本身的 Public IP。如此一來,外部網站(例如 Web Server)所記錄到的 Source IP 就是 Router 的 IP,而非 PC 的 Private IP。

SNAT 常用於以下場景:

Internet Sharing 一個公司或家庭網路內的多台設備分享同一個 Public IP 上網時,Router 使用 SNAT 技術把內部 Source IP(如 192.168.x.x)改為 Public IP,以便外網 Server 能正確回應。

Container Network 和 Hairpin NAT 如 Docker 中,當 Container 需要通過映射的 Port 訪問自己或其他 Container 時,SNAT(或 MASQUERADE,它是一種特殊形式的 SNAT)用來改寫 Source Address,使得回應路由可以正確返回。

DNAT:Destination Network Address Translation (目標網路地址轉換)

DNAT(Destination Network Address Translation)則改寫封包的目的地 IP 位址,典型的應用場景是把位於內網的 Web 伺服器透過防火牆的公網 IP 對外發布。例如,一台 Web 伺服器只擁有內網 IP,卻希望讓網際網路使用者能直接使用公網 IP 來存取。當外部客戶端發送封包時,目的地為該防火牆的公網 IP,而防火牆會將封包的目的地址動態改寫成 Web 伺服器的內網 IP,並把封包轉發至內網。最終,外部訪問就能穿透防火牆,抵達實際的內網伺服器,達成 DNAT 所謂的「目標地址」轉換。

DNAT 常用於以下場景:

Port Forwarding(連接埠轉發) 在家庭或企業網路中,外部訪問某個公共 IP 和埠號的流量可以經過 NAT 設備轉發到內部網路的特定伺服器。例如:外部訪問公網 IP 的 8080 埠流量會被轉發到內部 192.168.1.100 的 80 埠上。這裡就使用了 DNAT 改寫封包的目的地址與埠號。

Load Balancing(負載平衡) DNAT 可用於將到達某個入口點的流量分配到多個後端伺服器,以平衡負載。

MASQUERADE:地址偽裝

MASQUERADE 其實是 SNAT 的一種特例,能夠自動完成 SNAT。雖然在 iptables 中可以使用與 SNAT 類似的方式來實現轉換,但仍存在一些差異。最主要的不同點在於,使用 SNAT 時必須明確指定要轉換成的 IP,這個 IP 可以是一個或多個範圍。但如果系統採用 ADSL 這類動態撥號方式,每次撥號後出口 IP 都可能改變,便無法使用事先寫死的 SNAT 規則,因為規則裡的 IP 不會隨著撥號取得的新 IP 自動變更,導致我們必須頻繁手動修改 iptables,非常不方便。

正因如此,MASQUERADE 便應運而生。它會自動偵測網卡(例如 eth0)的當前動態 IP,無論 IP 變動多頻繁,都能在出站時自動將封包的來源 IP 改為網卡的最新 IP,如此就能大幅簡化維運工作。

SNAT 與 MASQUERADE 的用法範例

  1. SNAT(單一 IP)

    Terminal window
    1
    iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j SNAT --to-source 192.168.5.3

    此命令表示:將所有來源為 10.8.0.0/24 的封包,在透過 eth0 介面傳送出去時,將其來源 IP 改為 192.168.5.3

  2. SNAT(多個 IP 範圍)

    Terminal window
    1
    iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j SNAT --to-source 192.168.5.3-192.168.5.5

    此規則表示:將 10.8.0.0/24 網段的流量,根據特定演算法或機制,改寫為 192.168.5.3192.168.5.4192.168.5.5 等多個 IP 之一。

  3. MASQUERADE(自動抓取動態 IP)

    Terminal window
    1
    iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j MASQUERADE

    使用此命令,無需指定來源 IP,MASQUERADE 會自動取得 eth0 的當前 IP,讓封包傳送出去時統一使用該 IP 作為來源 IP。


總結:

  • SNATDNAT 分別針對封包的「Source」或「Destination」進行轉換。在實際應用中,我們常需要同時處理內網 Server 對外以及外網 Client 對內的流量,因此 SNAT 與 DNAT 經常搭配使用。
  • MASQUERADE 作為 SNAT 的一種特例,特別適合用於出口 IP 不固定、動態頻繁變更的環境,能為管理者省去手動修改規則的麻煩,讓網路地址轉換更自動化、更輕鬆。

分析:建立 Docker Container 前後的 iptables 與 NAT 變化

掌握必要的知識後,讓我們實際分析 iptables 和 NAT 的變化。首先,查看 Docker Network:

Terminal window
1
docker network ls
2
# output
3
NETWORK ID NAME DRIVER SCOPE
4
469fd7ab0fbd bridge bridge local
5
a2b456636301 host host local
6
e5238737e4cb none null local

這三個是 Docker 的預設網路。接著,使用以下指令建立一個 nginx container:

Terminal window
1
docker container run --name my-nginx-container -d -p 8080:80 nginx

讓我們觀察 iptables 和 nat 的變化。首先看 filter table:

1
iptables -t filter -nvL --line-number
2
# output
3
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
4
num pkts bytes target prot opt in out source destination
5
6
Chain FORWARD (policy DROP 0 packets, 0 bytes)
7
num pkts bytes target prot opt in out source destination
8
1 0 0 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
9
2 0 0 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
10
3 0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
11
4 0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
12
5 0 0 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
13
6 0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
14
15
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
45 collapsed lines
16
num pkts bytes target prot opt in out source destination
17
18
Chain DOCKER (1 references)
19
num pkts bytes target prot opt in out source destination
20
1 0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80
21
22
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
23
num pkts bytes target prot opt in out source destination
24
1 0 0 DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
25
2 0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
26
27
Chain DOCKER-ISOLATION-STAGE-2 (1 references)
28
num pkts bytes target prot opt in out source destination
29
1 0 0 DROP all -- * docker0 0.0.0.0/0 0.0.0.0/0
30
2 0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
31
32
Chain DOCKER-USER (1 references)
33
num pkts bytes target prot opt in out source destination
34
1 0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
35
36
###
37
38
iptables -t nat -nvL --line-number
39
# output
40
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
41
num pkts bytes target prot opt in out source destination
42
1 0 0 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
43
44
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
45
num pkts bytes target prot opt in out source destination
46
47
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
48
num pkts bytes target prot opt in out source destination
49
1 69 5003 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
50
1 218 16475 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
51
52
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
53
num pkts bytes target prot opt in out source destination
54
1 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
55
2 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
56
57
Chain DOCKER (2 references)
58
num pkts bytes target prot opt in out source destination
59
1 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
60
2 0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80

整理一下,只留下新增的規則:

Terminal window
1
*filter
2
Chain DOCKER (1 references)
3
num pkts bytes target prot opt in out source destination
4
1 0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80
5
6
*nat
7
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
8
num pkts bytes target prot opt in out source destination
9
2 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
10
11
Chain DOCKER (2 references)
12
num pkts bytes target prot opt in out source destination
13
2 0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80

使用 iptables-save 找到對應的項目:

Terminal window
1
*filter
2
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
3
4
*nat
5
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
6
7
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

解釋:filter 表的規則

Terminal window
1
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT

解讀:

  • -A DOCKER:在 filter 表的自訂 Chain DOCKER 中新增一條規則。
  • -d 172.17.0.2/32:目的 IP 為 172.17.0.2(容器在 docker0 bridge 上的虛擬網卡 IP)。
  • ! -i docker0:封包的輸入介面不是 docker0,表示該封包來自外部。
  • -o docker0:封包的輸出介面是 docker0,表示封包要傳送到 docker0 介面。
  • -p tcp -m tcp --dport 80:協定為 TCP,目的埠為 80。
  • -j ACCEPT:允許符合條件的封包通過。

目的: 此規則允許外部流量傳送到容器的 80 埠。

驗證步驟

開始之前,我們先備份 iptables:

Terminal window
1
sudo iptables-save > /tmp/iptables-backup.txt

接著使用 iptables -D 刪除規則,此時該條規則暫時失效

Terminal window
1
# iptables -D <CHAIN> <行號>
2
sudo iptables -D DOCKER 1

測試從 Host 外連線到 nginx 容器對應的 HOST_IP

。你應該會看到連線失敗的訊息。

最後,記得恢復 iptables:

Terminal window
1
sudo iptables-restore < /tmp/iptables-backup.txt

default


解釋: nat 表的規則

Terminal window
1
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE

解讀:

  • -A POSTROUTING:在 nat 表的 POSTROUTING Chain 中新增規則。
  • -s 172.17.0.2/32 -d 172.17.0.2/32:來源 IP 和目的 IP 同樣是 172.17.0.2,表示同一個容器自己連到自己(loopback/hairpin)的情境。
  • -p tcp -m tcp --dport 80:協定為 TCP,目的埠為 80。
  • -j MASQUERADE:對此流量進行 NAT 轉換(MASQUERADE 會動態改寫來源 IP/Port),使其能正常「環迴」回到同一個容器。

目的:
這是 Docker 用來處理「容器透過主機映射的 Port 存取自己」的情境(俗稱 Hairpin NAT)。舉例來說,當容器嘗試連到 host_ip:8080 時,最終需要轉回自己的 80 Port,此時就需要 MASQUERADE 來實現「自我存取」的連線。若沒有這個機制,封包在傳輸過程中可能會出現路由或 ARP 的錯亂。

default


Terminal window
1
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

解讀:

  • -A DOCKER:在 nat 表裡的自訂 Chain DOCKER 新增規則。
  • ! -i docker0:封包的輸入介面不是 docker0(意即從外部或主機進來)。
  • -p tcp -m tcp --dport 8080:協定為 TCP,目的埠為 8080。
  • -j DNAT --to-destination 172.17.0.2:80:進行目地位址轉換 (Destination NAT),將目的 IP/Port 改寫成 172.17.0.2:80

目的:
這正是 Port Mapping 的關鍵規則:

  • 當外界或本機對「Host 的 8080 Port」發起 TCP 連線,iptables 會把流量 DNAT 到容器的 172.17.0.2:80
  • 也就是說,外部連到 host:8080,最後轉到容器 IP:80(nginx)上,使你可以從外部直接以 http://HOST_IP:8080 連到容器裡面的服務。

default

補充: 解釋 DOCKER Chain 的來源

NAT 轉跳到 DOCKER 的條件有以下兩個:

Terminal window
1
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
2
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER

我們來看看簡單版 iptables 流程圖:

default

簡單解釋一下兩個 Chain 的差別:

PREROUTING

  • 主要處理外部網絡進入的封包(經過網卡的流量)。
  • 本地主機生成的封包不經過 PREROUTING,因為它們從來沒有經過網卡的輸入路徑。

OUTPUT

  • 處理所有本地主機生成的封包,包括發往本機的封包。
  • 如果 Docker 中需要處理本地主機生成的流量(例如連接 localhost:9091),則必須在 OUTPUT Chain中設置

其中規則的 --dst-type LOCAL 中的 LOCAL 代表”本地主機”,是指運行 iptables 的那台機器(例如 EC2 實例)的網路接口地址。相同的 network namespace 都算是 LOCAL 的範疇。 而使用 Docker Bridge 時,由於本質上是建立了另一個 network namespace,所以從容器 IP 對於 Host 的 iptables 來說屬於外網,會走 PREROUTING chain。

小結

使用 Docker,使用 bridge network 建立容器,並且指定 port forwarding 從容器 80 port 到 host 主機 8080 port (-p 8080:80)。會對 iptables 建立以下規則:

  1. 當外界或本機對「Host 的 8080 Port」發起 TCP 連線,iptables 會把流量 DNAT 到容器的 172.17.0.2:80
  2. 允許同一個容器透過主機映射的 Port 再回來連自己 (Hairpin NAT)
  3. 允許外部(非 docker0 Interface)進來、要轉送到容器 IP:80 的封包順利通行。

至於”允許容器對外部發起連線” 的規則,在第五章時已經做過了,規則如下:

Terminal window
1
# 允許: 所有預設 bridge 網段對外部連線
2
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
3
# 所有預設 bridge 網段連線到外部,做 SNAT 轉換
4
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
5
# 允許: 所有預設 bridge 網段,連線建立後返回的封包或與該連線相關的封包
6
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

大家可以用上面學習到的知識,試著解讀這些規則。

實作:Docker Style Port Forwarding

接下來我們要實作自己的 Container port forwarding,目標如下:

  1. 在 bridge 網路內,啟動 HTTP server,監聽位址 0.0.0.0:8081(等於在容器內啟動)
  2. 在 host 網路內,port forwarding Host 網路的 9091 port 到 bridge 網路的 8081 port
  3. 確保在 Host 網路內,可以透過 HOST_IP:9091 連線到 HTTP server
  4. 確保在另一個 EC2 網路,可以透過 HOST_IP:9091 連線到 HTTP server

製作 HTTP Server 執行檔

首先建立 Golang 專案,添加以下程式碼:

cmd/api/main.go
1
package main
2
3
import (
4
"fmt"
5
"net/http"
6
"os"
7
"strconv"
8
9
"github.com/go-chi/chi/v5"
10
"github.com/go-chi/cors"
11
)
12
13
type Config struct{}
14
15
func main() {
44 collapsed lines
16
app := Config{}
17
18
port := ":8080" // Default port
19
if len(os.Args) > 1 {
20
p, err := strconv.Atoi(os.Args[1])
21
if err != nil {
22
fmt.Println("Invalid port number:", err)
23
return
24
}
25
port = fmt.Sprintf(":%d", p)
26
}
27
srv := http.Server{
28
Addr: port,
29
Handler: app.routes(),
30
}
31
fmt.Printf("Server is listening on %s\n", port)
32
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
33
fmt.Println("Error starting server:", err)
34
}
35
}
36
37
func (app *Config) routes() http.Handler {
38
mux := chi.NewRouter()
39
40
mux.Use(cors.Handler(cors.Options{
41
AllowedOrigins: []string{"https://*", "http://*"},
42
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
43
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
44
ExposedHeaders: []string{"Link"},
45
AllowCredentials: true,
46
MaxAge: 300,
47
}))
48
49
mux.Get("/", app.HelloWorld)
50
51
return mux
52
}
53
54
func (app *Config) HelloWorld(w http.ResponseWriter, r *http.Request) {
55
_, err := w.Write([]byte("Hello World!"))
56
if err != nil {
57
http.Error(w, err.Error(), http.StatusInternalServerError)
58
}
59
}

編譯執行檔:

Terminal window
1
$env:GOOS = "linux"
2
$env:GOARCH = "amd64"
3
go build -o simpleServer cmd/api/main.go

執行 simpleServer,指定 8081 port,就可以啟動一個簡單的 Server:

Terminal window
1
./simpleServer 8081
2
# output
3
Server is listening on :8081

EC2 設定

為了方便施作,在既有的 Security Group 允許 TCP inbound:

default

simpleServer 執行檔上傳到 Host1 EC2:

Terminal window
1
scp -i </path/to/your-key.pem> </path/to/local-file> ec2-user@<EC2_IP或DNS>:</path/to/remote/directory>

測試連線:

Terminal window
1
curl localhost:8081
2
# output
3
Hello World!

在 ns1 運行 HTTP Server

在 ns1 開一個新的 bash shell:

Terminal window
1
sudo ip netns exec ns1 bash

使用 simpleServer 啟動 HTTP server:

Terminal window
1
# in ns1
2
./simpleServer 8081
3
# output
4
Server is listening on :8081

在 ns1 再開一個新的 bash shell,檢查 8081 Port 有沒有被佔用:

Terminal window
1
# in ns1
2
netstat -ano | grep 8081
3
# output
4
tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN off (0.00/0/0)

回到 root ns 的 bash shell,檢查 8081 Port 有沒有被佔用:

Terminal window
1
netstat -ano | grep 8081
2
# output
3
$

在 root ns 測試 HTTP server 連線:

Terminal window
1
curl 172.18.0.3:8081
2
# output
3
Hello World!

在 root ns 啟動 ns1 的 lo:

Terminal window
1
ip netns exec net1 ip link set lo up

在 ns1 的 bash shell,重新啟動 HTTP server,測試訪問自己:

Terminal window
1
# in ns1
2
curl localhost:8081
3
# output
4
Hello World!

準備測試環境

首先,我們將 Terminal 視窗切分,並準備好四個 Session,對應如下:

default

接著,測試 root ns -> ns1 以及 host2 -> host1 的連線是否暢通:

default

確認連線正常後,我們就可以開始添加規則了。

讓本地主機(Host1)可以訪問容器的 HTTP Server 服務

OUTPUT DNAT 規則

將本地主機到達本地主機 9091 Port 的 TCP 流量轉發到容器的 8081 Port。

完整的 DNAT 規則如下:

Terminal window
1
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
2
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

不透過 Docker Chain 處理,我們可以進一步簡化規則:

Terminal window
1
-A OUTPUT \
2
! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL \
3
-p tcp --dport 8080 \
4
-j DNAT --to-destination 172.17.0.2:80

再將規則中的 bridge, dport 和 dnat 修改成我們的案例:

Terminal window
1
sudo iptables -t nat -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL \
2
-p tcp -m tcp --dport 9091 -j DNAT --to-destination 172.18.0.3:8081

操作結果如下:

default

讓外網 (Host2) 可以訪問 Host1 容器的 HTTP Server 服務

我們需要同時設置 SNAT, DNAT 才能形成完整的 Port Forwarding

PREROUTING DNAT 規則

將外部到達本地主機 9091 Port 的 TCP 流量轉發到容器的 8081 Port。

完整的 DNAT 規則如下:

Terminal window
1
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
2
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

不透過 Docker Chain 處理,我們可以進一步簡化規則:

Terminal window
1
-A PREROUTING \
2
-m addrtype --dst-type LOCAL \
3
! -i docker0 \
4
-p tcp --dport 8080 \
5
-j DNAT --to-destination 172.17.0.2:80

再將規則中的 bridge, dport 和 dnat 修改成我們的案例:

Terminal window
1
sudo iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL \
2
! -i docker1 -p tcp -m tcp --dport 9091 -j DNAT --to-destination 172.18.0.3:8081

Filter 規則

允許外網封包轉送到 HTTP Server

Terminal window
1
sudo iptables -t filter -A FORWARD -d 172.18.0.3/32 ! -i docker1 -o docker1 -p tcp -m tcp --dport 8081 -j ACCEPT

操作結果如下:

default

結論

在本章中,我們深入探討了 Docker 容器的 Port Forwarding 機制,並實際動手實作。主要學習到以下幾點:

NAT 的基本概念與應用

  • 了解 SNAT、DNAT 和 MASQUERADE 的差異與使用場景
  • 掌握 Docker 如何運用 NAT 實現容器網路的連通性

Docker Port Forwarding 的實現原理

  • Docker 透過 iptables 的 DNAT 規則實現 Port Mapping
  • 使用 MASQUERADE 處理 Hairpin NAT(容器自訪問)的情況
  • Filter 表的規則確保封包能順利通過

到這篇為止,我們差不多了解了 Docker Bridge 網路的全貌。之後可能會出個補充篇,再寫一篇這個系列的總整理篇做個結尾。

本文標題:從 Linux 基礎實現 Docker Bridge 網路:一步步理解容器通訊 (6)
文章作者:Vincent Lin
發布時間:2025-01-14