在 Linux中,Namespace 和 Cgroups 是如何實(shí)現(xiàn)資源隔離?
Linux 內(nèi)核提供了多種機(jī)制來實(shí)現(xiàn)系統(tǒng)資源的隔離和管理,這篇文章,我們來詳細(xì)分析兩種關(guān)鍵的技術(shù):Namespace 和 Cgroups。
一、Namespace 詳解
Namespace(命名空間,也稱名稱空間)是 Linux 內(nèi)核用于隔離系統(tǒng)資源,使得不同的進(jìn)程組可以擁有各自獨(dú)立的資源視圖。Namespace 的核心思想是通過將系統(tǒng)資源劃分為不同的命名空間,進(jìn)而實(shí)現(xiàn)資源的隔離。
Namespace通常包含以下幾種類型:
- PID Namespace
- Mount Namespace
- UTS Namespace
- IPC Namespace
- Network Namespace
- User Namespace
1. PID Namespace
PID Namespace 用于隔離進(jìn)程 ID 空間。每個(gè) PID Namespace 都有自己獨(dú)立的進(jìn)程 ID 號(hào),父 Namespace 可以查看和管理子 Namespace 中的進(jìn)程,但反之則不行。這種機(jī)制使得在容器中運(yùn)行的進(jìn)程可以擁有從 1 開始的 PID。
# 創(chuàng)建新的 PID Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
unshare -p -f --mount-proc bash
2. Mount Namespace
Mount Namespace 用于隔離掛載點(diǎn)。不同的 Mount Namespace 可以擁有各自獨(dú)立的文件系統(tǒng)視圖。這樣一來,在一個(gè) Namespace 中對(duì)文件系統(tǒng)的修改不會(huì)影響到其他 Namespace。
# 創(chuàng)建新的 Mount Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
unshare -m bash
3. UTS Namespace
UTS (UNIX Time-Sharing) Namespace 用于隔離主機(jī)名和域名。不同的 UTS Namespace 可以擁有不同的主機(jī)名和域名,這對(duì)于容器化應(yīng)用非常有用。
# 創(chuàng)建新的 UTS Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
unshare -u bash
hostname new_hostname
4. IPC Namespace
IPC (Inter-Process Communication) Namespace 用于隔離進(jìn)程間通信資源,如消息隊(duì)列、信號(hào)量和共享內(nèi)存。不同的 IPC Namespace 之間的通信資源是隔離的。
# 創(chuàng)建新的 IPC Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
unshare -i bash
5. Network Namespace
Network Namespace 用于隔離網(wǎng)絡(luò)資源,如網(wǎng)絡(luò)接口、路由表、防火墻規(guī)則等。每個(gè) Network Namespace 可以擁有獨(dú)立的網(wǎng)絡(luò)設(shè)備和配置。
# 創(chuàng)建新的 Network Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
ip netns add mynamespace
ip netns exec mynamespace bash
6. User Namespace
User Namespace 用于隔離用戶和用戶組 ID。它允許在不同的 Namespace 中使用相同的用戶 ID,但這些 ID 在不同的 Namespace 中是獨(dú)立的。這樣一來,即使在容器中運(yùn)行的進(jìn)程以 root 身份運(yùn)行,也不會(huì)擁有對(duì)宿主系統(tǒng)的 root 權(quán)限。
# 創(chuàng)建新的 User Namespace 并運(yùn)行一個(gè) Bash 進(jìn)程
unshare -U bash
7. 無法被 Namespace
盡管 Linux的 Namespace機(jī)制提供了對(duì)多種系統(tǒng)資源的隔離,但并不是所有的系統(tǒng)資源都能被 Namespace隔離,以下是一些不能被 Namespace隔離的資源及其原因:
- 內(nèi)核模塊: 內(nèi)核模塊(Kernel Modules)在整個(gè)系統(tǒng)中是全局共享的。加載或卸載一個(gè)內(nèi)核模塊會(huì)影響到所有Namespace中的進(jìn)程。
- 內(nèi)核參數(shù): 通過sysctl命令設(shè)置的內(nèi)核參數(shù)(如/proc/sys下的參數(shù))是全局的,無法在不同的Namespace中進(jìn)行獨(dú)立設(shè)置。
- 硬件資源:硬件資源是物理存在的,無法通過軟件機(jī)制進(jìn)行隔離。
- CPU:盡管Cgroups可以對(duì)CPU資源進(jìn)行分配和限制,但CPU本身是一個(gè)物理資源,無法在不同的Namespace中進(jìn)行隔離。
- 內(nèi)存:Cgroups可以對(duì)內(nèi)存資源進(jìn)行分配和限制,但物理內(nèi)存本身無法在不同的Namespace中進(jìn)行隔離。
- 磁盤:磁盤設(shè)備是物理存在的,無法在不同的Namespace中進(jìn)行隔離。盡管可以通過Cgroups對(duì)磁盤I/O進(jìn)行限制,但磁盤設(shè)備本身是共享的。
- 時(shí)間:系統(tǒng)時(shí)間(如系統(tǒng)時(shí)鐘和硬件時(shí)鐘)在整個(gè)系統(tǒng)中是共享的,無法在不同的Namespace中進(jìn)行獨(dú)立設(shè)置。
- 安全機(jī)制:一些系統(tǒng)級(jí)的安全機(jī)制無法在不同的Namespace中進(jìn)行隔離。
- SELinux:SELinux(Security-Enhanced Linux)是一種安全模塊,它的策略在整個(gè)系統(tǒng)中是全局的,無法在不同的Namespace中進(jìn)行獨(dú)立設(shè)置。
- AppArmor:類似于SELinux,AppArmor也是一種安全機(jī)制,它的配置和策略在整個(gè)系統(tǒng)中是全局的。
- 系統(tǒng)日志:系統(tǒng)日志(如/var/log下的日志文件)在整個(gè)系統(tǒng)中是共享的,無法在不同的Namespace中進(jìn)行獨(dú)立管理。
- 特殊設(shè)備文件:一些特殊的設(shè)備文件(如/dev下的某些設(shè)備文件)在不同的Namespace中是共享的,無法進(jìn)行隔離。例如,/dev/null、/dev/zero等設(shè)備文件在整個(gè)系統(tǒng)中是全局的。
二、Cgroups 詳解
1. 什么是Cgroups?
Cgroups (Control Groups,控制組)是 Linux 內(nèi)核的一個(gè)特性,用于限制、記錄和隔離一組進(jìn)程的資源使用(CPU、內(nèi)存、磁盤 I/O、網(wǎng)絡(luò)等)。
Cgroups 通過將進(jìn)程分組,然后對(duì)這些組應(yīng)用資源限制來工作,核心組件包括:
- Subsystem: 資源控制的具體實(shí)現(xiàn),如 CPU、內(nèi)存等。
- Hierarchy: Subsystem 的組織結(jié)構(gòu),類似于文件系統(tǒng)的層級(jí)結(jié)構(gòu)。
- Cgroup: Hierarchy 中的一個(gè)節(jié)點(diǎn),代表一組進(jìn)程。
2. Cgroups 的子系統(tǒng)
Cgroups 支持多種子系統(tǒng),每種子系統(tǒng)負(fù)責(zé)不同的資源控制:
- cpu: 控制 CPU 資源的分配。
- cpuacct: 提供 CPU 資源使用的統(tǒng)計(jì)信息。
- memory: 控制內(nèi)存資源的分配和使用。
- blkio: 控制塊設(shè)備的 I/O 操作。
- net_cls: 控制網(wǎng)絡(luò)資源的分類。
- devices: 控制設(shè)備的訪問權(quán)限。
- freezer: 暫停和恢復(fù)進(jìn)程。
3. 創(chuàng)建和管理 Cgroups
通過命令行工具 cgcreate、cgset 和 cgexec 可以方便地創(chuàng)建和管理 Cgroups。
# 創(chuàng)建一個(gè)新的 Cgroup
cgcreate -g cpu,memory:/mygroup
# 設(shè)置 CPU 使用限制
cgset -r cpu.shares=512 mygroup
# 設(shè)置內(nèi)存使用限制
cgset -r memory.limit_in_bytes=256M mygroup
# 將一個(gè)進(jìn)程加入到 Cgroup
cgexec -g cpu,memory:mygroup /bin/bash
4. Cgroups v2
Cgroups v2 是 Cgroups 的第二個(gè)版本,提供了更為統(tǒng)一和簡(jiǎn)化的接口。Cgroups v2 的主要特點(diǎn)包括:
- 統(tǒng)一的層級(jí)結(jié)構(gòu),所有子系統(tǒng)共享同一個(gè)層級(jí)。
- 更為簡(jiǎn)化的配置接口,減少了配置的復(fù)雜性。
- 提高了資源控制的精度和靈活性。
# 掛載 Cgroups v2
mount -t cgroup2 none /sys/fs/cgroup
# 創(chuàng)建一個(gè)新的 Cgroup
mkdir /sys/fs/cgroup/mygroup
# 設(shè)置 CPU 使用限制
echo 50000 > /sys/fs/cgroup/mygroup/cpu.max
# 設(shè)置內(nèi)存使用限制
echo 256M > /sys/fs/cgroup/mygroup/memory.max
# 將一個(gè)進(jìn)程加入到 Cgroup
echo $$ > /sys/fs/cgroup/mygroup/cgroup.procs
三、Namespace 和 Cgroups 的結(jié)合
Namespace 和 Cgroups 的結(jié)合使用是容器技術(shù)的基礎(chǔ),Namespace 提供了進(jìn)程級(jí)別的隔離,而 Cgroups 則用于資源的分配和限制,通過這兩種機(jī)制,可以創(chuàng)建高效且安全的容器化環(huán)境。
容器的創(chuàng)建
以下是一個(gè)簡(jiǎn)單的示例,展示如何使用 Namespace 和 Cgroups 創(chuàng)建一個(gè)容器:
# 創(chuàng)建新的 Namespace
unshare -p -f -m -u -i -n --mount-proc bash
# 設(shè)置主機(jī)名
hostname container
# 掛載新的文件系統(tǒng)
mount -t tmpfs none /tmp
# 創(chuàng)建新的 Cgroup
cgcreate -g cpu,memory:/container
# 設(shè)置 CPU 和內(nèi)存限制
cgset -r cpu.shares=512 container
cgset -r memory.limit_in_bytes=256M container
# 將當(dāng)前進(jìn)程加入到 Cgroup
cgclassify -g cpu,memory:container $$
在上述示例中,我們首先創(chuàng)建了一個(gè)新的 Namespace,然后設(shè)置了主機(jī)名并掛載了新的文件系統(tǒng)。接著,我們創(chuàng)建了一個(gè)新的 Cgroup,并設(shè)置了 CPU 和內(nèi)存限制。最后,我們將當(dāng)前進(jìn)程加入到 Cgroup。
四、總結(jié)
Namespace 和 Cgroups 是 Linux 內(nèi)核提供的兩種關(guān)鍵機(jī)制,用于實(shí)現(xiàn)系統(tǒng)資源的隔離和管理。Namespace 提供了進(jìn)程級(jí)別的隔離,使得不同的進(jìn)程組可以擁有各自獨(dú)立的資源視圖,而 Cgroups 則用于資源的分配和限制,通過將進(jìn)程分組,然后對(duì)這些組應(yīng)用資源限制來工作。結(jié)合使用這兩種機(jī)制,可以創(chuàng)建高效且安全的容器化環(huán)境。