DEV Community

JH5
JH5

Posted on • Originally published at Medium

Docker/K8s 網路基礎:從手動操作 Linux Network Namespace 開始

Docker/K8s 網路基礎:從手動操作 Linux Network Namespace 開始

在現代的雲端運算與容器化技術(如 Docker、Kubernetes)中,網路的隔離是一個基本的核心概念,在Multi-tenancy的環境中,我們不只希望隔離Process的檔案系統和Process ID,更重要的是要隔離彼此之間的網路環境,而Linux…

UpdatedMarch 24, 2026•3 min read

Docker/K8s 網路基礎:從手動操作 Linux Network Namespace 開始

JJhihHao Wu**近期研究重點包含 AI Agent 的供應鏈攻擊、PII 偵測模型評估,以及醫療 AI 在臨床流程中的安全落地。

在這裡,我分享深度技術實測報告(如 NVIDIA NeMo, WildGuard)與職場技術成長心得,致力於在 AI 浪潮中打造具備資安韌性的解決方案。

On this page

Docker/K8s 網路基礎:從手動操作 Linux Network Namespace 開始網路介面在 Namespace 之間移動1. 建立 Namespace 並移入介面處理「撞名」移動介面並同時重新命名當 Namespace 被刪除時會發生什麼?實體介面的「回家」之路與命名衝突systemd 與可預測的網路介面命名

Docker/K8s 網路基礎:從手動操作 Linux Network Namespace 開始

Linux networking

在現代的雲端運算與容器化技術(如 Docker、Kubernetes)中,網路的隔離是一個基本的核心概念,在Multi-tenancy的環境中,我們不只希望隔離Process的檔案系統和Process ID,更重要的是要隔離彼此之間的網路環境,而Linux 核心提供了一個強大的功能來實現這一點,就是 網路命名空間 (Network Namespace)

簡單來說,你可以把每個 Network Namespace 想像成宿舍內一個個獨立的「網路房間」,每個房間都有自己專屬的網路設備、IP 位址、路由表、防火牆規則等等,這也代表,在 namespace1 這個房間裡的程序,看不到也無法直接存取 namespace2 房間的網路,實現了完美的網路隔離。

而這一切的基礎都建立在一個關鍵規則上:一個網路介面(Network Interface)在同一時間只能存在於一個 Network Namespace 中,就像前面的例子,每一扇門一次只能安裝在一間房間上。

那我們該如何管理這些「門」,在不同的「房間」之間移動它們呢?

網路介面在 Namespace 之間移動

要在不同的 Namespace 之間移動網路介面,最常用的工具就是 ip 指令。

1. 建立 Namespace 並移入介面

讓我們先從一個最簡單的範例開始。假設我們要建立一個新的網路空間 namespace1,並創建一個虛擬的 dummy0 介面,然後將它移入 namespace1

步驟 1:建立新的 Network Namespace

# 建立一個名為 namespace1 的網路命名空間  
$ ip netns add namespace1  

# 確認 ns1 裡面只有一個預設的 lo (loopback) 介面  
$ ip netns exec namespace1 ip link  
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
Enter fullscreen mode Exit fullscreen mode

步驟 2:在root Namespace 建立一個虛擬介面

# 建立一個名為 dummy0 的 dummy 類型介面  
$ ip link add dummy0 type dummy  

# 確認一下,現在 dummy0 存在於我們操作的預設環境中  
$ ip link show dummy0  
24: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether 4e:3d:fe:03:2c:c8 brd ff:ff:ff:ff:ff:ff
Enter fullscreen mode Exit fullscreen mode

步驟 3:將 dummy0 移入 ns1

# 使用 ip link set 指令將 dummy0 移動到 namespace1  
$ ip link set dummy0 netns namespace1
Enter fullscreen mode Exit fullscreen mode

上面的指令,其實是透過 Netlink 向 Linux 核心發送了一個 RTM_NEWLINK 請求(一般是網路介面的狀態有發生變動時會觸發),並帶上目標 Namespace 的識別資訊。

步驟 4:驗證結果

# root Namespace 中,dummy0 消失了  
$ ip link show dummy0  
Device "dummy0" not found.  

# 在 namespace1 中,我們成功找到了 dummy0  
$ ip netns exec namespace1 ip link  
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00  
4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether e2:79:ba:8f:ad:3e brd ff:ff:ff:ff:ff:ff
Enter fullscreen mode Exit fullscreen mode

處理「撞名」移動介面並同時重新命名

介面名稱其實在現實世界是一種麻煩事,如果在目標 Namespace namespace1 中,已經有一個叫做 dummy0 的介面了,會發生什麼事?

# 假設 namespace1 裡面已經有 dummy0 了,我們再移一個dummy0進去  
$ ip link add dummy0 type dummy   
$ ip link set dummy0 netns namespace1  
RTNETLINK answers: File exists
Enter fullscreen mode Exit fullscreen mode

系統會很直接地告訴你:「檔案已存在 (File exists)」,操作失敗,因為在同一個 Namespace 內,介面名稱必須是唯一的,也因此,ip 指令允許我們在移動的同時,為介面指定一個新的名字。

# 在移動 dummy0 到 ns1 的同時,將它改名為 dummy1  
$ ip link set dummy0 netns namespace1 name dummy1  

# 檢查 namespace1,可以看到新的介面 dummy1  
$ ip netns exec namespace1 ip link  
...  
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00  
4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether e2:79:ba:8f:ad:3e brd ff:ff:ff:ff:ff:ff  
5: dummy1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether e2:79:ba:8f:ad:3e brd ff:ff:ff:ff:ff:ff
Enter fullscreen mode Exit fullscreen mode

這次的操作,在送給核心的 Netlink 訊息中,除了目標 Namespace,還多了一個 IFLA_IFNAME 屬性,明確告知了新的介面名稱。

當 Namespace 被刪除時會發生什麼?

我們把介面搬進了 Namespace,那如果這個 Namespace 被刪除了呢?比如 ip netns del namespace1,裡面的介面會何去何從?

答案取決於介面的「類型」:

  • 虛擬介面 (Virtual Interface):像是 dummy, veth, bridge 等,這些介面是依附於 Namespace 的,因此當 Namespace 消失時,它們也會跟著直接被刪除

  • 實體介面 (Physical Interface):像是你的實體網卡 eth0enp3s0,這些是實際的硬體設備,不能隨便刪除,也因為這樣,當它們所在的 Namespace 被刪除時,核心會自動將它們移回到最初的 Root Namespace

實體介面的「回家」之路與命名衝突

當實體介面要「回家」時,也可能遇到撞名問題,如果Root Namespace 已經有一個同名介面了怎麼辦?

核心的處理邏輯如下:

  • 嘗試使用它原本的名字。

  • 如果原名已被佔用,核心會幫它取一個新的名字,通常是 dev%d 的格式(%d 是介面的索引編號 ifindex)。

  • 如果連 dev%d 都被佔用了,就會使用 dev%%d 樣板來確保能找到一個獨一無二的名字。

讓我們來看一個有趣的實驗:

# 1. 將實體介面 dev0 移入 namespace1  
$ ip link set dev0 netns namespace1
Enter fullscreen mode Exit fullscreen mode
# 2. 在根 Namespace 建立一個同名的虛擬介面 dev0  
$ ip link add dev0 type dummy
Enter fullscreen mode Exit fullscreen mode
# 3. 此時根 Namespace 有一個虛擬的 dev0,namespace1 有一個實體的 dev0  
# 現在,我們刪除 namespace1  
$ ip netns del namespace1
Enter fullscreen mode Exit fullscreen mode
# 4. 檢查根 Namespace 的介面  
$ ip link  
...  
# 這是我們手動建立的虛擬 dev0  
4: dev0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff  
# 這是從 namespace1 回家的實體介面,因為 dev0 被佔用,被自動改名為 dev1  
6: dev1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
    link/ether 11:22:33:44:55:66 brd ff:ff:ff:ff:ff:ff
Enter fullscreen mode Exit fullscreen mode

這個自動重新命名的機制,確保了系統的穩定性,避免了因 Namespace 刪除而導致實體設備遺失或衝突。

systemd 與可預測的網路介面命名

在過去,網路介面名稱是 eth0, eth1... 這種不穩定的方式,順序可能因為開機時核心偵測到設備的順序而改變。

systemd 後來加入了可預測網路介面命名機制 (Predictable Network Interface Names),它會根據硬體的韌體資訊、PCI 插槽位置、MAC 位址等穩定特徵來為介面命名,例如 enp3s0(表示在 PCI bus 3, slot 0 上的乙太網路卡)或 wlp2s0(表示在 PCI bus 2, slot 0 上的無線網卡),總共有五種命名方式,也可以關掉自動命名。

同時,systemd-udevd 服務在開機時監聽核心事件,並根據 /etc/udev/rules.d/ 中的規則為新發現的網路設備賦予這些穩定的名稱,這樣衣來,無論開機順序如何,你的網卡名稱始終如一,大大簡化了網路設定和管理。

上面這些跟Docker/K8S有什麼關係?

我一直以來個人理解是這樣的XD 如果有錯誤請鞭小力一點

  • Linux Namespace & Cgroups:是每個宿舍的房間與門禁,每個房間內有哪些資源可以用,有誰可以進出。

  • Systemd:是每個樓層(每台主機/節點)的管理員,確保水電(Kubelet、Container Runtime)正常供應。

  • Kubernetes:是整棟宿舍大樓的舍監管理層,負責規劃誰該住什麼房間(Pod)、房間要幾間(ReplicaSet),以及如何管理所有房間(service、LB等),或是各種需求(規劃新生,轉學生申請宿舍)時的安排等。

簡單來說,Kubernetes 進行最上層的規劃與決策,將任務派發給節點上的 systemd 所管理的 kubeletkubelet 再指揮 container runtime,最終由 container runtime 利用 Linux Namespace 和 Cgroups 這些核心功能,完成容器的建立與運行。

# devops# docker# kubernetes

Top comments (0)