Docker —— 隔離的基本操作(2)
- unshare
- `unshare` 命令詳解
- 基本語法
- 常用選項
- 常用示例
- 實際應用場景
- 注意事項
- 與 Docker 的關系
- 1. 執行命令
- 2. 修改主機名
- 3. 退出命名空間
- 4. 驗證宿主機主機名
- 關鍵原理
- 類比 Docker 容器
- 總結
- 實戰操作一(PID 隔離)
- 關于 `unshare --pid --fork --mount-proc` 的深入解釋
- 1. `--fork` 的作用
- 2. `--pid` 的隔離特性
- 3. `--mount-proc` 的必要性
- 完整命令的意義
- 常見問題
- Q1:不加 `--fork` 會怎樣?
- Q2:不加 `--mount-proc` 會怎樣?
- Q3:為什么需要 `sudo`?
- 總結
- 實戰操作二(Mount 隔離)
我們上次簡單介紹了一些關于隔離的一些基本操作,如果不熟悉的小伙伴可以點擊這里:
https://blog.csdn.net/qq_67693066/article/details/147712428
我們今天主要來操作一下隔離,如何實現:
unshare
unshare
命令詳解
unshare
是 Linux 系統中用于創建新命名空間(namespace)并運行程序的命令,它是 Linux 容器技術(如 Docker)的基礎工具之一。通過 unshare
可以創建隔離的運行環境。
基本語法
unshare [選項] [--] [程序 [參數...]]
常用選項
短參數 | 長參數 | 含義 |
---|---|---|
-i | --ipc | 不共享 IPC 空間(隔離進程間通信:消息隊列、共享內存等) |
-m | --mount | 不共享 Mount 空間(隔離文件系統掛載點) |
-n | --net | 不共享 Net 空間(隔離網絡棧:IP、端口、路由等) |
-p | --pid | 不共享 PID 空間(隔離進程 ID,需配合 --fork 和 --mount-proc 使用) |
-u | --uts | 不共享 UTS 空間(隔離主機名和域名) |
-U | --user | 不共享用戶命名空間(隔離用戶和組 ID,普通用戶可用) |
-V | --version | 查看版本信息 |
--fork | 創建子進程并在子進程中執行 unshare (通常與 --pid 共用,使子進程成為 PID 1) | |
--mount-proc | 在新 PID 命名空間中掛載 /proc 文件系統(確保 ps 、top 等命令正常工作) |
常用示例
-
創建新的 mount 命名空間:
unshare --mount
在這個新命名空間中的掛載操作不會影響主系統
-
創建 PID 命名空間(類似容器環境):
sudo unshare --pid --fork --mount-proc bash
在這個新環境中,bash 將成為 PID 1 的進程
-
創建網絡命名空間:
sudo unshare --net
這個新環境將有獨立的網絡棧
-
創建完整的隔離環境:
sudo unshare --pid --fork --mount-proc --net --mount --uts bash
-
創建用戶命名空間(不需要 root 權限):
unshare --user --map-root-user
-
在新命名空間中運行特定程序:
unshare --pid --fork --mount-proc -- sleep 1000
實際應用場景
-
測試軟件安裝:
unshare --mount bash mkdir /tmp/testroot mount --bind /tmp/testroot /tmp/testroot mount --make-private /tmp/testroot mount --bind /path/to/package /tmp/testroot chroot /tmp/testroot /bin/bash
-
創建臨時網絡環境:
sudo unshare --net ip link set lo up ip addr add 192.168.1.100/24 dev lo
-
安全測試:
unshare --user --map-root-user --pid --fork --mount-proc bash
注意事項
- 大多數命名空間需要 root 權限,除了用戶命名空間
- 使用
--pid
時通常需要同時使用--fork
和--mount-proc
- 命名空間中的修改不會影響主系統
- 可以使用
nsenter
命令進入已存在的命名空間
與 Docker 的關系
Docker 等容器技術底層就是使用 unshare
類似的機制創建隔離環境。例如:
# 類似于 Docker 容器的基礎隔離
sudo unshare --pid --fork --mount-proc --net --mount --uts --ipc bash
unshare
是理解 Linux 容器技術的重要工具,通過它可以深入了解 Linux 的命名空間隔離機制。
我們來簡單使用一下:
這段命令演示了使用 unshare
創建 UTS 命名空間(主機名隔離)的過程。以下是逐步解釋:
1. 執行命令
sudo unshare -u /bin/bash
-u
(--uts
):創建新的 UTS 命名空間,隔離主機名和域名。/bin/bash
:在新命名空間中啟動 Bash shell。- 需要
sudo
因為 UTS 命名空間默認需要 root 權限。
2. 修改主機名
hostname test1
hostname
- 在新 UTS 命名空間中,將主機名修改為
test1
。 hostname
命令驗證修改成功,此時 僅影響新命名空間。
3. 退出命名空間
exit
- 退出 Bash shell 后,回到原來的 UTS 命名空間(宿主機環境)。
4. 驗證宿主機主機名
hostname
- 顯示
localhost.localdomain
,證明宿主機的主機名 未被修改。 - 因為之前的
hostname test1
只在新創建的 UTS 命名空間中生效。
關鍵原理
-
UTS 命名空間隔離:
- 每個 UTS 命名空間維護獨立的主機名和域名。
- 子命名空間的修改不會影響父命名空間(宿主機)。
-
作用域:
unshare -u
創建的子進程及其后代進程會繼承新的 UTS 命名空間。- 退出子進程后,命名空間自動銷毀(除非使用
--persistent
等選項)。
類比 Docker 容器
Docker 容器啟動時也會創建獨立的 UTS 命名空間:
# 在容器內修改主機名不影響宿主機
docker run -it --hostname mycontainer alpine sh
總結
- 發生了什么:
通過unshare -u
創建了一個臨時的隔離環境,在其中修改的主機名僅在該環境內有效,退出后宿主機環境保持不變。 - 為什么需要:
這種隔離機制是容器技術的基礎,允許不同環境擁有獨立的主機名配置,避免沖突。
實戰操作一(PID 隔離)
在主機上執行 ps -ef,可以看到進程列表如下,其中啟動進程 PID 1 為 init 進程:
我們打開另外一個 shell ,執行下面命令創建一個 bash 進程,并且新建一個 PID
Namespace:
unshare --fork --pid --mount-proc /bin/bash
執行 exit 退出進程
關于 unshare --pid --fork --mount-proc
的深入解釋
1. --fork
的作用
-
核心問題:
當使用--pid
創建新的 PID 命名空間時,新命名空間需要有一個獨立的進程樹,且第一個進程(PID 1)必須是該命名空間內的進程。- 如果不加
--fork
,unshare
自身進程(父進程)會作為新命名空間的初始進程,但該父進程 并不屬于新命名空間,導致內核無法正確初始化 PID 命名空間,報錯Cannot allocate memory
。
- 如果不加
-
解決方案:
--fork
會讓unshare
先創建一個子進程(fork
),再在該子進程中調用unshare
創建新命名空間。此時子進程成為新命名空間的 PID 1(類似init
進程),符合內核要求。
2. --pid
的隔離特性
-
僅隔離 PID:
--pid
僅隔離進程 ID 視圖,其他資源(如網絡、掛載點等)仍與宿主機共享。- 新命名空間內的進程無法看到宿主機其他進程,但宿主機仍能看到新命名空間內的進程(只是 PID 不同)。
-
對比完整容器:
若需完全隔離,需組合其他命名空間(如--net --mount --uts
)。
3. --mount-proc
的必要性
-
/proc
文件系統的特殊性:
Linux 的/proc
是一個虛擬文件系統,動態反映當前命名空間的進程信息。- 默認情況下,
/proc
顯示 宿主機全局進程信息,與新 PID 命名空間隔離的視圖沖突。
- 默認情況下,
-
掛載新
/proc
的作用:
--mount-proc
會自動在新命名空間中重新掛載/proc
,使其僅包含 當前命名空間及其子命名空間的進程信息。- 這樣,
ps
、top
等命令才能正確顯示當前命名空間內的進程。
- 這樣,
-
與
--mount
的關系:
--mount-proc
隱含了掛載點隔離(類似--mount
),但專門針對/proc
優化,避免手動掛載的復雜性。
完整命令的意義
sudo unshare --pid --fork --mount-proc bash
- 流程:
--fork
創建子進程作為 PID 1。--pid
在新子進程中初始化獨立的 PID 命名空間。--mount-proc
掛載隔離后的/proc
,確保進程工具正常工作。- 啟動
bash
,成為新命名空間的主進程。
常見問題
Q1:不加 --fork
會怎樣?
- 內核拒絕初始化 PID 命名空間,報錯
Cannot allocate memory
,因為缺少合法的 PID 1 進程。
Q2:不加 --mount-proc
會怎樣?
ps
/top
仍顯示宿主機所有進程,破壞 PID 隔離的語義。
Q3:為什么需要 sudo
?
- 創建 PID 命名空間默認需要
root
權限(涉及系統級進程管理)。
總結
參數 | 作用 | 必要性 |
---|---|---|
--pid | 創建獨立的 PID 命名空間 | 核心功能 |
--fork | 確保新命名空間有合法的 PID 1 進程 | 必須配合 --pid 使用 |
--mount-proc | 掛載隔離后的 /proc ,使進程工具正常工作 | 強烈推薦(否則隔離不完整) |
這種機制是 Linux 容器(如 Docker)的基礎:通過組合多個命名空間(--pid --net --mount
等)和 --mount-proc
,實現進程、網絡、文件系統等資源的隔離。
實戰操作二(Mount 隔離)
打開第一個 shell 窗口 A,執行命令, df -h ,查看主機默認命名空間的磁盤掛載情
況:
打開一個新的 shell 窗口 B,執行 Mount 隔離命令
unshare --mount --fork /bin/bash
在窗口 B 中添加新的磁盤掛載
dd if=/dev/zero of=fdimage.img bs=8k count=10240
mkfs -t ext4 ./fdimage.img
mount ./fdimage.img 文件路徑
在窗口 B 掛載的磁盤中添加文件
echo "Hello world!" > ./tmpmount/hello.txt
查看窗口 A 中的磁盤掛載信息
查看窗口 B 中的文件信息
查看窗口 A 中的文件信息,可以看到窗口 B 中新建的文件和磁盤掛載在主機的窗
口中并沒有,說明我們實現了文件系統隔離。
窗口 B 執行 exit,退出