詳解Linux中的命名空間

背景
從Linux 2.6.24版的內(nèi)核開始,Linux 就支持6種不同類型的命名空間。它們的出現(xiàn),使用戶創(chuàng)建的進(jìn)程能夠與系統(tǒng)分離得更加徹底,從而不需要使用更多的底層虛擬化技術(shù)。
- CLONE_NEWIPC: 進(jìn)程間通信(IPC)的命名空間,可以將 SystemV 的 IPC 和 POSIX 的消息隊(duì)列獨(dú)立出來。
CLONE_NEWPID: 進(jìn)程命名空間。空間內(nèi)的PID 是獨(dú)立分配的,意思就是命名空間內(nèi)的虛擬 PID 可能會與命名空間外的 PID 相沖突,于是命名空間內(nèi)的 PID 映射到命名空間外時會使用另外一個 PID。比如說,命名空間內(nèi)第一個 PID 為1,而在命名空間外就是該 PID 已被 init 進(jìn)程所使用。
CLONE_NEWNET: 網(wǎng)絡(luò)命名空間,用于隔離網(wǎng)絡(luò)資源(/proc/net、IP 地址、網(wǎng)卡、路由等)。后臺進(jìn)程可以運(yùn)行在不同命名空間內(nèi)的相同端口上,用戶還可以虛擬出一塊網(wǎng)卡。
CLONE_NEWNS: 掛載命名空間,進(jìn)程運(yùn)行時可以將掛載點(diǎn)與系統(tǒng)分離,使用這個功能時,我們可以達(dá)到 chroot 的功能,而在安全性方面比 chroot 更高。
CLONE_NEWUTS: UTS 命名空間,主要目的是獨(dú)立出主機(jī)名和網(wǎng)絡(luò)信息服務(wù)(NIS)。
CLONE_NEWUSER: 用戶命名空間,同進(jìn)程 ID 一樣,用戶 ID 和組 ID 在命名空間內(nèi)外是不一樣的,并且在不同命名空間內(nèi)可以存在相同的 ID。
下面我們介紹一下進(jìn)程命名空間和網(wǎng)絡(luò)命名空間。
進(jìn)程命名空間
本文用 C 語言介紹上述概念,因?yàn)檠菔具M(jìn)程命名空間的時候需要用到 C 語言。下面的測試過程在 Debian 6 和 Debian 7 上執(zhí)行。首先,在棧內(nèi)分配一頁內(nèi)存空間,并將指針指向內(nèi)存頁的末尾。這里我們使用 alloca() 函數(shù)來分配內(nèi)存,不要用 malloc() 函數(shù),它會把內(nèi)存分配在堆上。
然后使用 clone() 函數(shù)創(chuàng)建子進(jìn)程,傳入我們的子??臻g地址 "mem",并指定命名空間的標(biāo)記。同時我們還指定“callee”作為子進(jìn)程運(yùn)行的函數(shù)。
clone 之后我們要在父進(jìn)程中等待子進(jìn)程先退出,否則的話,父進(jìn)程會繼續(xù)運(yùn)行下去,并馬上進(jìn)程結(jié)束,留下子進(jìn)程變成孤兒進(jìn)程:
{
continue;
}
最后當(dāng)子進(jìn)程退出后,我們會回到 shell 界面,并返回子進(jìn)程的退出碼。
{
return WEXITSTATUS(r);
}
return EXIT_FAILURE;
上文介紹的 callee 函數(shù)功能如下:
{
int ret;
mount("proc", "/proc", "proc", 0, "");
setgid(u);
setgroups(0, NULL);
setuid(u);
ret = execl("/bin/bash", "/bin/bash", NULL);
return ret;
}
程序掛載了 /proc 文件系統(tǒng),設(shè)置用戶 ID 和組 ID,值都為“u”,然后運(yùn)行 /bin/bash 程序,LXC 是一個操作系統(tǒng)級的虛擬化工具,使用 cgroups 和命名空間來完成資源的分離?,F(xiàn)在我們把所有代碼放在一起,變量“u”的值設(shè)為65534,在 Debian 系統(tǒng)中,這是“nobody”和“nogroup”:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <grp.h>
#include <alloca.h>
#include <errno.h>
#include <sched.h>
static int callee();
const int u = 65534;
int main(int argc, char *argv[])
{
int r;
pid_t mypid;
void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);
mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);
while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
{
continue;
}
if (WIFEXITED(r))
{
return WEXITSTATUS(r);
}
return EXIT_FAILURE;
}
static int callee()
{
int ret;
mount("proc", "/proc", "proc", 0, "");
setgid(u);
setgroups(0, NULL);
setuid(u);
ret = execl("/bin/bash", "/bin/bash", NULL);
return ret;
}
執(zhí)行以下命令來運(yùn)行上面的代碼:
root@w:~/pen/tmp# ./ns
nobody@w:~/pen/tmp$ id
uid=65534(nobody) gid=65534(nogroup)
nobody@w:~/pen/tmp$ ps auxw
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
nobody 1 0.0 0.0 4620 1816 pts/1 S 21:21 0:00 /bin/bash
nobody 5 0.0 0.0 2784 1064 pts/1 R+ 21:21 0:00 ps auxw
nobody@w:~/pen/tmp$
注意上面的結(jié)果,UID 和 GID 被設(shè)置成 nobody 和 nogroup 了,特別是 ps 工具只輸出兩個進(jìn)程,它們的 ID 分別是1和5(LCTT注:這就是上文介紹 CLONE_NEWPID 時提到的功能,在線程所在的命名空間內(nèi),進(jìn)程 ID 可以為1,映射到命名空間外是另外一個 PID;而命名空間外的 ID 為1的進(jìn)程一直是 init)。
網(wǎng)絡(luò)命名空間
接下來輪到使用 ip netns 來設(shè)置網(wǎng)絡(luò)的命名空間。第一步先確定當(dāng)前系統(tǒng)沒有命名空間:
Object "netns" is unknown, try "ip help".
如果報了上述錯誤,你需要更新你的系統(tǒng)內(nèi)核,以及 ip 工具程序。這里假設(shè)你的內(nèi)核版高于2.6.24,ip 工具版本也差不多,高于2.6.24(LCTT注:ip 工具由 iproute 安裝包提供,此安裝包版本與內(nèi)核版本相近)。更新好后,ip netns list 在沒有命名空間存在的情況下不會輸出任務(wù)信息。加個名為“ns1”的命名空間看看:
root@w:~# ip netns list
ns1
列出網(wǎng)卡:
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
創(chuàng)建新的虛擬網(wǎng)卡,并加到命名空間。虛擬網(wǎng)卡需要成對創(chuàng)建,互相關(guān)聯(lián)——就像交叉電纜一樣:
root@w:~# ip link list
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
3: veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
4: veth0: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether f2:f7:5e:e2:22:ac brd ff:ff:ff:ff:ff:ff
這個時候 ifconfig -a 命令也能顯示新添加的 veth0 和 veth1 兩塊網(wǎng)卡。
很好,現(xiàn)在將這兩份塊網(wǎng)卡加到命名空間中去。注意一下,下面的 ip netns exec 命令用于將后面的命令在命名空間中執(zhí)行(LCTT注:下面的結(jié)果顯示了在 ns1 這個網(wǎng)絡(luò)命名空間中,只存在 lo 和 veth1 兩塊網(wǎng)卡):
root@w:~# ip netns exec ns1 ip link list
1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth1: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether d2:e9:52:18:19:ab brd ff:ff:ff:ff:ff:ff
這個時候 ifconfig -a 命令只能顯示 veth0,不能顯示 veth1,因?yàn)楹笳攥F(xiàn)在在 ns1 命名空間中。
如果想刪除 veth0/veth1,可以執(zhí)行下面的命令:
我們可以為 veth0 分配 IP 地址:
在命名空間內(nèi)為 veth1 分配 IP 地址:
在命名空間內(nèi)外執(zhí)行 ip addr list 命令:
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
inet 192.168.3.122/24 brd 192.168.3.255 scope global eth0
inet6 fe80::20c:29ff:fe65:259e/64 scope link
valid_lft forever preferred_lft forever
6: veth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 86:b2:c7:bd:c9:11 brd ff:ff:ff:ff:ff:ff
inet 192.168.5.5/24 brd 192.168.5.255 scope global veth0
inet6 fe80::84b2:c7ff:febd:c911/64 scope link
valid_lft forever preferred_lft forever
root@w:~# ip netns exec ns1 ip addr list
1: lo: mtu 65536 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
inet 192.168.5.10/24 brd 192.168.5.255 scope global veth1
inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link
valid_lft forever preferred_lft forever
在命名空間內(nèi)外查看路由表:
default via 192.168.3.1 dev eth0 proto static
192.168.3.0/24 dev eth0 proto kernel scope link src 192.168.3.122
192.168.5.0/24 dev veth0 proto kernel scope link src 192.168.5.5
root@w:~# ip netns exec ns1 ip route list
192.168.5.0/24 dev veth1 proto kernel scope link src 192.168.5.10
最后,將虛擬網(wǎng)卡連到物理網(wǎng)卡上,我們需要用到橋接。這里做的是將 veth0 橋接到 eth0,而 ns1 命名空間內(nèi)則使用 DHCP 自動獲取 IP 地址:
root@w:~# brctl addif br0 eth0
root@w:~# brctl addif br0 veth0
root@w:~# ifconfig eth0 0.0.0.0
root@w:~# ifconfig veth0 0.0.0.0
root@w:~# dhclient br0
root@w:~# ip addr list br0
7: br0: mtu 1500 qdisc noqueue state UP
link/ether 00:0c:29:65:25:9e brd ff:ff:ff:ff:ff:ff
inet 192.168.3.122/24 brd 192.168.3.255 scope global br0
inet6 fe80::20c:29ff:fe65:259e/64 scope link
valid_lft forever preferred_lft forever
為網(wǎng)橋 br0 分配的 IP 地址為192.168.3.122/24。接下來為命名空間分配地址:
root@w:~# ip netns exec ns1 ip addr list
1: lo: mtu 65536 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 12:bd:b6:76:a6:eb brd ff:ff:ff:ff:ff:ff
inet 192.168.3.248/24 brd 192.168.3.255 scope global veth1
inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link
valid_lft forever preferred_lft forever
現(xiàn)在, veth1 的 IP 被設(shè)置成 192.168.3.248/24 了。
相關(guān)文章
Fedora Linux 42 穩(wěn)定版發(fā)布: 帶來大量新功能和軟件更新
Fedora 42昨日發(fā)布,這是 Red Hat 贊助開發(fā)的杰出前沿 Linux 發(fā)行版的最新版,包含大量新功能和軟件更新,使其成為 2025 年上半年發(fā)布的一款出色的 Linux 操作系統(tǒng)之一,內(nèi)2025-04-16如何在Linux查看硬盤信息? 查看Linux硬盤大小類型和硬件信息的5種方法
使用Linux系統(tǒng)的過程中,查看和了解硬盤信息是非常重要的工作,尤其是對于系統(tǒng)管理員而言,那么在Linux系統(tǒng)中如何查看硬盤信息?以下是具體內(nèi)容介紹2025-03-12如何在 Linux 中查看 CPU 詳細(xì)信息? 3招輕松查看CPU型號、核心數(shù)和溫度
在日常運(yùn)維工作中,獲取 CPU 信息是系統(tǒng)運(yùn)維管理員常見的工作內(nèi)容,無論是為了性能調(diào)優(yōu)、硬件升級還是僅僅滿足好奇心2025-03-11什么是 Arch Linux? 獨(dú)樹一幟的Arch Linux發(fā)行版分析
Arch Linux是為簡化,優(yōu)化,現(xiàn)代化,實(shí)用主義,用戶中心和多功能性而創(chuàng)建Linux發(fā)行版,究竟是什么讓 Arch 與眾不同?下面我們就來簡要解讀2025-02-19如何在Linux環(huán)境下制作 Win11裝機(jī)U盤?
一直用的linux辦公,想要將筆記本電腦從 Linux 系統(tǒng)切換回 Windows 11,我們可以制作一個win11裝機(jī)u盤,詳細(xì)如下2025-02-17Rsnapshot怎么用? 基于Rsync的強(qiáng)大Linux備份工具使用指南
Rsnapshot 不僅可以備份本地文件,還能通過 SSH 備份遠(yuǎn)程文件,接下來詳細(xì)介紹如何安裝、配置和使用 Rsnapshot,包括創(chuàng)建每小時、每天、每周和每月的本地備份,以及如何進(jìn)2025-02-06Linux Kernel 6.13發(fā)布:附更新內(nèi)容及新特性解讀
Linux 內(nèi)核 6.13 正式發(fā)布,新版本引入了惰性搶占支持,簡化內(nèi)核搶占邏輯,通過減少與調(diào)度器相關(guān)的調(diào)用次數(shù),讓內(nèi)核在運(yùn)行時表現(xiàn)更優(yōu),從而提高效率2025-01-23五大特性引領(lǐng)創(chuàng)新! 深度操作系統(tǒng) deepin 25 Preview預(yù)覽版發(fā)布
今日,深度操作系統(tǒng)正式推出deepin 25 Preview版本,該版本集成了五大核心特性:磐石系統(tǒng)、全新DDE、Treeland窗口合成器、AI For OS以及Distrobox子系統(tǒng)2025-01-18Linux Mint Xia 22.1重磅發(fā)布: 重要更新一覽
Beta 版 Linux Mint“Xia” 22.1 發(fā)布,新版本基于 Ubuntu 24.04,內(nèi)核版本為 Linux 6.8,這次更新帶來了諸多優(yōu)化和改進(jìn),進(jìn)一步鞏固了 Mint 在 Linux 桌面操作系統(tǒng)領(lǐng)域的2025-01-16LinuxMint怎么安裝? Linux Mint22下載安裝圖文教程
Linux Mint22發(fā)布以后,有很多新功能,很多朋友想要下載并安裝,該怎么操作呢?下面我們就來看看詳細(xì)安裝指南2025-01-16