溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Linux中的命名空間

發(fā)布時(shí)間:2021-09-03 15:13:33 來源:億速云 閱讀:181 作者:chen 欄目:系統(tǒng)運(yùn)維

本篇內(nèi)容介紹了“Linux中的命名空間 ”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

背景

從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)程命名空間??臻g內(nèi)的PID 是獨(dú)立分配的,意思就是命名空間內(nèi)的虛擬 PID 可能會(huì)與命名空間外的 PID 相沖突,于是命名空間內(nèi)的 PID 映射到命名空間外時(shí)會(huì)使用另外一個(gè) PID。比如說,命名空間內(nèi)第一個(gè) PID 為1,而在命名空間外就是該 PID 已被 init 進(jìn)程所使用。
        CLONE_NEWNET: 網(wǎng)絡(luò)命名空間,用于隔離網(wǎng)絡(luò)資源(/proc/net、IP 地址、網(wǎng)卡、路由等)。后臺(tái)進(jìn)程可以運(yùn)行在不同命名空間內(nèi)的相同端口上,用戶還可以虛擬出一塊網(wǎng)卡。
        CLONE_NEWNS: 掛載命名空間,進(jìn)程運(yùn)行時(shí)可以將掛載點(diǎn)與系統(tǒng)分離,使用這個(gè)功能時(shí),我們可以達(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)程命名空間的時(shí)候需要用到 C 語言。下面的測試過程在 Debian 6 和 Debian 7 上執(zhí)行。首先,在棧內(nèi)分配一頁內(nèi)存空間,并將指針指向內(nèi)存頁的末尾。這里我們使用 alloca() 函數(shù)來分配內(nèi)存,不要用 malloc() 函數(shù),它會(huì)把內(nèi)存分配在堆上。

   

代碼如下:

void *mem = alloca(sysconf(_SC_PAGESIZE)) + sysconf(_SC_PAGESIZE);

然后使用 clone() 函數(shù)創(chuàng)建子進(jìn)程,傳入我們的子??臻g地址 "mem",并指定命名空間的標(biāo)記。同時(shí)我們還指定“callee”作為子進(jìn)程運(yùn)行的函數(shù)。

   

代碼如下:

mypid = clone(callee, mem, SIGCHLD | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_FILES, NULL);

clone 之后我們要在父進(jìn)程中等待子進(jìn)程先退出,否則的話,父進(jìn)程會(huì)繼續(xù)運(yùn)行下去,并馬上進(jìn)程結(jié)束,留下子進(jìn)程變成孤兒進(jìn)程:

   

代碼如下:

while (waitpid(mypid, &r, 0) < 0 && errno == EINTR)
   {
       continue;
   }

最后當(dāng)子進(jìn)程退出后,我們會(huì)回到 shell 界面,并返回子進(jìn)程的退出碼。

   

代碼如下:

if (WIFEXITED(r))
   {
       return WEXITSTATUS(r);
   }
   return EXIT_FAILURE;

上文介紹的 callee 函數(shù)功能如下:

   

代碼如下:

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;
   }

程序掛載了 /proc 文件系統(tǒng),設(shè)置用戶 ID 和組 ID,值都為“u”,然后運(yùn)行 /bin/bash 程序,LXC 是一個(gè)操作系統(tǒng)級(jí)的虛擬化工具,使用 cgroups 和命名空間來完成資源的分離?,F(xiàn)在我們把所有代碼放在一起,變量“u”的值設(shè)為65534,在 Debian 系統(tǒng)中,這是“nobody”和“nogroup”:

   

代碼如下:

#define _GNU_SOURCE
   #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# gcc -O -o ns.c -Wall -Werror -ansi -c89 ns.c
   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 工具只輸出兩個(gè)進(jìn)程,它們的 ID 分別是1和5(LCTT注:這就是上文介紹 CLONE_NEWPID 時(shí)提到的功能,在線程所在的命名空間內(nèi),進(jìn)程 ID 可以為1,映射到命名空間外是另外一個(gè) PID;而命名空間外的 ID 為1的進(jìn)程一直是 init)。
網(wǎng)絡(luò)命名空間

接下來輪到使用 ip netns 來設(shè)置網(wǎng)絡(luò)的命名空間。第一步先確定當(dāng)前系統(tǒng)沒有命名空間:

   

代碼如下:

root@w:~# ip netns list
   Object "netns" is unknown, try "ip help".

如果報(bào)了上述錯(cuò)誤,你需要更新你的系統(tǒng)內(nèi)核,以及 ip 工具程序。這里假設(shè)你的內(nèi)核版高于2.6.24,ip 工具版本也差不多,高于2.6.24(LCTT注:ip 工具由 iproute 安裝包提供,此安裝包版本與內(nèi)核版本相近)。更新好后,ip netns list 在沒有命名空間存在的情況下不會(huì)輸出任務(wù)信息。加個(gè)名為“ns1”的命名空間看看:

   

代碼如下:

root@w:~# ip netns add ns1
   root@w:~# ip netns list
   ns1

列出網(wǎng)卡:

   

代碼如下:

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

創(chuàng)建新的虛擬網(wǎng)卡,并加到命名空間。虛擬網(wǎng)卡需要成對(duì)創(chuàng)建,互相關(guān)聯(lián)&mdash;&mdash;就像交叉電纜一樣:

   

代碼如下:

root@w:~# ip link add veth0 type veth peer name veth2
   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: veth2:  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

這個(gè)時(shí)候 ifconfig -a 命令也能顯示新添加的 veth0 和 veth2 兩塊網(wǎng)卡。

很好,現(xiàn)在將這兩份塊網(wǎng)卡加到命名空間中去。注意一下,下面的 ip netns exec 命令用于將后面的命令在命名空間中執(zhí)行(LCTT注:下面的結(jié)果顯示了在 ns1 這個(gè)網(wǎng)絡(luò)命名空間中,只存在 lo 和 veth2 兩塊網(wǎng)卡):

   

代碼如下:

root@w:~# ip link set veth2 netns ns1
   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: veth2:  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

這個(gè)時(shí)候 ifconfig -a 命令只能顯示 veth0,不能顯示 veth2,因?yàn)楹笳攥F(xiàn)在在 ns1 命名空間中。

如果想刪除 veth0/veth2,可以執(zhí)行下面的命令:

   

代碼如下:

ip netns exec ns1 ip link del veth2

我們可以為 veth0 分配 IP 地址:

   

代碼如下:

ifconfig veth0 192.168.5.5/24

在命名空間內(nèi)為 veth2 分配 IP 地址:

   

代碼如下:

ip netns exec ns1 ifconfig veth2 192.168.5.10/24 up

在命名空間內(nèi)外執(zhí)行 ip addr list 命令:

   

代碼如下:

root@w:~# 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: veth2:  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 veth2
       inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link
          valid_lft forever preferred_lft forever

在命名空間內(nèi)外查看路由表:

   

代碼如下:

root@w:~# ip route list
   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 veth2  proto kernel  scope link  src 192.168.5.10

最后,將虛擬網(wǎng)卡連到物理網(wǎng)卡上,我們需要用到橋接。這里做的是將 veth0 橋接到 eth0,而 ns1 命名空間內(nèi)則使用 DHCP 自動(dòng)獲取 IP 地址:

   

代碼如下:

root@w:~# brctl addbr br0
   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 dhclient veth2
   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: veth2:  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 veth2
       inet6 fe80::10bd:b6ff:fe76:a6eb/64 scope link
          valid_lft forever preferred_lft forever

現(xiàn)在, veth2 的 IP 被設(shè)置成 192.168.3.248/24 了。

“Linux中的命名空間 ”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI