12.2 命名空間

命名空間是 Linux 核心一個強大的屬性。每個容器都有自己單獨的命名空間,執行在其中的應用都像是在獨立的作業系統中執行一樣。命名空間保證了容器之間彼此互不影響。

12.2.1 什麼是 Namespace

**Namespace 是 Linux 核心提供的資源隔離機制,它讓容器內的程序髣髴執行在獨立的作業系統中。**Namespace 是容器技術的核心基礎之一。它回答了一個關鍵問題:如何讓一個程序 『以為』 自己獨佔整個系統?

flowchart LR subgraph Host ["宿主機視角"] direction TB H1["PID 1: systemd"] H2["PID 2: sshd"] H3["PID 3: dockerd"] H4["PID 1234: nginx"] H5["PID 1235: nginx worker"] end subgraph Container ["容器內視角"] direction TB C1["PID 1: nginx
← 容器認為自己是 PID 1"] C2["PID 2: nginx worker"] end H4 -. "(實際是宿主機的 1234)" .- C1

12.2.2 Namespace 的型別

Linux 核心(5.6+)共提供 8 種 Namespace。Docker 容器預設使用其中 7 種(不含 Time):

Namespace 隔離內容 容器中的效果
PID 程序 ID 容器內 PID 從 1 開始,看不到其他容器和宿主機程序
NET 網路棧 獨立的網絡卡、IP 地址、連接埠、路由表
MNT 掛載點 獨立的檔案系統檢視,自己的根目錄
UTS 主機名 獨立的主機名和網域名稱
IPC 程序間通訊 獨立的訊號量、訊息佇列、共享記憶體
USER 使用者/組 ID 容器內的 root 可以對映為宿主機的普通使用者
Cgroup Cgroup 根目錄 隔離 cgroup 層級檢視 (Linux 4.6+)
Time 系統時鐘 隔離 CLOCK_MONOTONIC 和 CLOCK_BOOTTIME (Linux 5.6+)

12.2.3 PID Namespace

PID Namespace 負責程序 ID 的隔離,使得容器內的程序彼此不可見。

PID 的作用

隔離程序 ID,讓每個容器有自己的程序編號空間。

PID 隔離效果

## 宿主機上檢視程序

$ ps aux | grep nginx
root     12345  0.0  0.1  nginx: master process
root     12346  0.0  0.1  nginx: worker process

## 容器內檢視程序

$ docker exec mycontainer ps aux
PID   USER     COMMAND
  1   root     nginx: master process    ← 在容器內是 PID 1
  2   root     nginx: worker process

PID 關鍵點

  • 容器內的 PID 1 程序特殊重要——它是容器的主程序,退出則容器停止
  • 容器內無法看到宿主機或其他容器的程序
  • 宿主機可以看到所有容器內的程序 (但 PID 不同)

12.2.4 NET Namespace

NET Namespace 負責網路棧的隔離,包括網絡卡、路由表和 iptables 規則等。

NET 的作用

隔離網路棧,每個容器擁有獨立的網路環境。

NET 隔離效果

flowchart LR subgraph Host ["宿主機"] direction TB H1["eth0: 192.168.1.10
連接埠 80 可用"] H2["docker0: 172.17.0.1"] end subgraph Container ["容器"] direction TB C1["eth0: 172.17.0.2
連接埠 80 可用"] C2["(veth pair 連線)"] end H2 <--> C2

NET 關鍵點

  • 每個容器有獨立的網絡卡、IP、路由表、iptables 規則
  • 多個容器可以監聽相同連接埠 (如都監聽 80)
  • Docker 使用 veth pair 連線容器網路和宿主機網橋

12.2.5 MNT Namespace

MNT Namespace 負責檔案系統掛載點的隔離,確保容器看到獨立的檔案系統檢視。

MNT 的作用

隔離檔案系統掛載點,每個容器有自己的根目錄。

MNT 隔離效果

宿主機檔案系統:                  容器內看到的:
/                               /  ← 容器的根目錄
├── bin/                        ├── bin/
├── home/                       ├── home/
├── var/                        ├── var/
│   └── lib/                    │   └── lib/
│       └── docker/             │
│           └── overlay2/       │
│               └── merged/ ────┼─── 這個目錄成為容器的 /
└── ...                         └── ...

與 chroot 的區別

屬性 chroot MNT Namespace
安全性 可以逃逸 更安全
掛載隔離 完全隔離
/proc/mounts 共享 獨立

12.2.6 UTS Namespace

UTS Namespace 主要用於隔離主機名和網域名稱。

UTS 的作用

隔離主機名和網域名稱,讓每個容器可以有自己的主機名。

UTS 隔離效果

## 宿主機

$ hostname
my-server

## 容器內

$ docker run --hostname mycontainer ubuntu hostname
mycontainer

UTS = 『UNIX Time-sharing System』,是歷史遺留的名稱。


12.2.7 IPC Namespace

IPC Namespace 用於隔離程序間通訊資源,如 System V IPC 和 POSIX 訊息佇列。

IPC 的作用

隔離 System V IPC 和 POSIX 訊息佇列。

隔離的資源

  • 訊號量 (semaphores)
  • 訊息佇列 (message queues)
  • 共享記憶體 (shared memory)

IPC 關鍵點

  • 同一容器內的程序可以透過 IPC 通訊
  • 不同容器的程序無法透過 IPC 通訊 (除非顯式共享)

12.2.8 USER Namespace

USER Namespace 允許將容器內的使用者 ID 對映到宿主機的不同使用者 ID。

USER 的作用

隔離使用者和組 ID,實現許可權隔離。

USER 隔離效果

flowchart LR subgraph Container ["容器內"] direction TB C1["UID 0 (root)"] C2["UID 1 (daemon)"] end subgraph Host ["宿主機"] direction TB H1["UID 100000
← 非特權使用者"] H2["UID 100001"] end C1 -- 對映 --> H1 C2 -- 對映 --> H2

安全意義

容器內的 root 使用者可以對映為宿主機上的普通使用者,即使容器被突破,攻擊者在宿主機上也只有普通許可權。

💡 筆者建議:生產環境建議啟用 User Namespace,增強安全性。


12.2.9 動手實驗:體驗 Namespace

使用 unshare 指令可以在不使用 Docker 的情況下體驗 Namespace:

實驗 1:UTS Namespace

## 建立新的 UTS namespace 並啟動 shell

$ sudo unshare --uts /bin/bash

## 修改主機名(隻影響這個 namespace)

$ hostname container-test
$ hostname
container-test

## 退出後檢視宿主機主機名(未改變)

$ exit
$ hostname
my-server

實驗 2:PID Namespace

## 建立新的 PID 和 MNT namespace

$ sudo unshare --pid --mount --fork /bin/bash

## 掛載新的 /proc

$ mount -t proc proc /proc

## 檢視程序(只能看到當前 shell)

$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   8960  4516 pts/0    S    10:00   0:00 /bin/bash
root         8  0.0  0.0  10072  3200 pts/0    R+   10:00   0:00 ps aux

實驗 3:NET Namespace

## 建立新的網路 namespace

$ sudo unshare --net /bin/bash

## 檢視網路介面(只有 lo)

$ ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

12.2.10 Namespace 的侷限性

Namespace 提供了隔離但不是安全邊界:

方面 說明
共享核心 所有容器共享宿主機核心,核心漏洞可能影響所有容器
部分資源未隔離 /proc、/sys 部分內容仍可見;Time Namespace (Linux 5.6+) 雖已可用,但 Docker 預設不啟用
非虛擬化 比虛擬機隔離性弱

需要更強隔離時,可考慮 gVisor、Kata Containers 等安全容器方案。


第 101 页,共 196 页
使用 mdPress 构建