這篇文章主要介紹“Namespace的作用是什么”,在日常操作中,相信很多人在Namespace的作用是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Namespace的作用是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
10年積累的做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先做網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有東港免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
Namespace 是 Linux 內(nèi)核的一個(gè)特性,該特性可以實(shí)現(xiàn)在同一主機(jī)系統(tǒng)中,對進(jìn)程 ID、主機(jī)名、用戶 ID、文件名、網(wǎng)絡(luò)和進(jìn)程間通信等資源的隔離。Docker 利用 Linux 內(nèi)核的 Namespace 特性,實(shí)現(xiàn)了每個(gè)容器的資源相互隔離,從而保證容器內(nèi)部只能訪問到自己 Namespace 的資源。
目前 Linux 內(nèi)核中提供了 8 種類型的 Namespace:
Mount Namespace 是 Linux 內(nèi)核實(shí)現(xiàn)的第一個(gè) Namespace,從內(nèi)核 2.4.19 版本開始加入。它可以用來隔離不同的進(jìn)程或者進(jìn)程組看到的掛載點(diǎn)。通俗地說,就是可以實(shí)現(xiàn)在不同的進(jìn)程中看到不同的掛載目錄。使用 Mount Namespace 可以實(shí)現(xiàn)容器內(nèi)只能看到自己的掛載信息,在容器內(nèi)的掛載操作不會(huì)影響主機(jī)的掛載目錄。
下面我們通過一個(gè)實(shí)例來演示下 Mount Namespace。在演示之前,我們先來認(rèn)識一個(gè)命令行工具 unshare。unshare 是 util-linux 工具包中的一個(gè)工具,CentOS 7 系統(tǒng)默認(rèn)已經(jīng)集成了該工具,使用 unshare 命令可以實(shí)現(xiàn)創(chuàng)建并訪問不同類型的 Namespace。
首先我們使用以下命令創(chuàng)建一個(gè) bash 進(jìn)程并且新建一個(gè) Mount Namespace:
#新建一個(gè) Mount Namespace root@docker-demo ~]# unshare --mount --fork /bin/bash
執(zhí)行完上述命令后,這時(shí)我們已經(jīng)在主機(jī)上創(chuàng)建了一個(gè)新的 Mount Namespace,并且當(dāng)前命令行窗口加入了新創(chuàng)建的 Mount Namespace。下面我通過一個(gè)例子來驗(yàn)證下,在獨(dú)立的 Mount Namespace 內(nèi)創(chuàng)建掛載目錄是不影響主機(jī)的掛載目錄的。
然后在 /tmp 目錄下創(chuàng)建一個(gè)目錄,創(chuàng)建好目錄后使用 mount 命令掛載一個(gè) tmpfs 類型的目錄:
[root@docker-demo ~]# mkdir /tmp/tmpfs [root@docker-demo ~]# mount -t tmpfs -o size=20m tmpfs /tmp/tmpfs
然后使用 df 命令查看一下已掛載的目錄信息:
[root@docker-demo ~]# df -h 文件系統(tǒng) 容量 已用 可用 已用% 掛載點(diǎn) /dev/mapper/centos-root 50G 15G 36G 29% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup tmpfs 3.9G 8.9M 3.9G 1% /run tmpfs 797M 8.0K 797M 1% /run/user/42 tmpfs 797M 0 797M 0% /run/user/0 /dev/sda1 1014M 222M 793M 22% /boot /dev/mapper/centos-home 142G 40M 142G 1% /home tmpfs 20M 0 20M 0% /tmp/tmpfs #剛剛掛載的目錄
可以看到 /tmp/tmpfs 目錄已經(jīng)被正確掛載。為了驗(yàn)證主機(jī)上并沒有掛載此目錄,我們新打開一個(gè)命令行窗口,同樣執(zhí)行 df 命令查看主機(jī)的掛載信息:
root@docker-demo ~]# df -hT 文件系統(tǒng) 類型 容量 已用 可用 已用% 掛載點(diǎn) devtmpfs devtmpfs 3.9G 0 3.9G 0% /dev tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs tmpfs 3.9G 9.0M 3.9G 1% /run tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/mapper/centos-root xfs 50G 15G 36G 29% / /dev/sda1 xfs 1014M 222M 793M 22% /boot /dev/mapper/centos-home xfs 142G 40M 142G 1% /home tmpfs tmpfs 797M 8.0K 797M 1% /run/user/42 tmpfs tmpfs 797M 0 797M 0% /run/user/0
通過上面輸出可以看到主機(jī)上并沒有掛載 /tmp/tmpfs,可見我們獨(dú)立的 Mount Namespace 中執(zhí)行 mount 操作并不會(huì)影響主機(jī)。
為了進(jìn)一步驗(yàn)證我們的想法,我們繼續(xù)在當(dāng)前命令行窗口查看一下當(dāng)前進(jìn)程的 Namespace 信息,命令如下:
[root@docker-demo ~]# ls -l /proc/self/ns/ 總用量 0 lrwxrwxrwx. 1 root root 0 3月 21 19:58 cgroup -> cgroup:[4026531835] lrwxrwxrwx. 1 root root 0 3月 21 19:58 ipc -> ipc:[4026531839] lrwxrwxrwx. 1 root root 0 3月 21 19:58 mnt -> mnt:[4026532670] lrwxrwxrwx. 1 root root 0 3月 21 19:58 net -> net:[4026531992] lrwxrwxrwx. 1 root root 0 3月 21 19:58 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 3月 21 19:58 pid_for_children -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 3月 21 19:58 time -> time:[4026531834] lrwxrwxrwx. 1 root root 0 3月 21 19:58 time_for_children -> time:[4026531834] lrwxrwxrwx. 1 root root 0 3月 21 19:58 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 3月 21 19:58 uts -> uts:[4026531838]
然后新打開一個(gè)命令行窗口,使用相同的命令查看一下主機(jī)上的 Namespace 信息:
[root@docker-demo ~]# ls -l /proc/self/ns/ 總用量 0 lrwxrwxrwx. 1 root root 0 3月 21 19:58 cgroup -> cgroup:[4026531835] lrwxrwxrwx. 1 root root 0 3月 21 19:58 ipc -> ipc:[4026531839] lrwxrwxrwx. 1 root root 0 3月 21 19:58 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 3月 21 19:58 net -> net:[4026531992] lrwxrwxrwx. 1 root root 0 3月 21 19:58 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 3月 21 19:58 pid_for_children -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 3月 21 19:58 time -> time:[4026531834] lrwxrwxrwx. 1 root root 0 3月 21 19:58 time_for_children -> time:[4026531834] lrwxrwxrwx. 1 root root 0 3月 21 19:58 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 3月 21 19:58 uts -> uts:[4026531838]
通過對比兩次命令的輸出結(jié)果,我們可以看到,除了 Mount Namespace 的 ID 值不一樣外,其他Namespace 的 ID 值均一致。
通過以上結(jié)果我們可以得出結(jié)論,使用 unshare 命令可以新建 Mount Namespace,并且在新建的 Mount Namespace 內(nèi) mount 是和外部完全隔離的。
PID Namespace 的作用是用來隔離進(jìn)程。在不同的 PID Namespace 中,進(jìn)程可以擁有相同的 PID 號,利用 PID Namespace 可以實(shí)現(xiàn)每個(gè)容器的主進(jìn)程為 1 號進(jìn)程,而容器內(nèi)的進(jìn)程在主機(jī)上卻擁有不同的PID。例如一個(gè)進(jìn)程在主機(jī)上 PID 為 122,使用 PID Namespace 可以實(shí)現(xiàn)該進(jìn)程在容器內(nèi)看到的 PID 為 1。
下面我們通過一個(gè)實(shí)例來演示下 PID Namespace的作用。首先我們使用以下命令創(chuàng)建一個(gè) bash 進(jìn)程,并且新建一個(gè) PID Namespace:
[root@docker-demo ~]# unshare --pid --fork --mount-proc /bin/bash [root@docker-demo ~]#
執(zhí)行完上述命令后,我們在主機(jī)上創(chuàng)建了一個(gè)新的 PID Namespace,并且當(dāng)前命令行窗口加入了新創(chuàng)建的 PID Namespace。在當(dāng)前的命令行窗口使用 ps aux 命令查看一下進(jìn)程信息:
[root@docker-demo ~]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 1.7 0.0 116752 4884 pts/0 S 19:59 0:00 /bin/bash root 31 7.0 0.0 151124 3872 pts/0 R+ 19:59 0:00 ps aux
通過上述命令輸出結(jié)果可以看到當(dāng)前 Namespace 下 bash 為 1 號進(jìn)程,而且我們也看不到主機(jī)上的其他進(jìn)程信息。
UTS Namespace 主要是用來隔離主機(jī)名的,它允許每個(gè) UTS Namespace 擁有一個(gè)獨(dú)立的主機(jī)名。例如我們的主機(jī)名稱為 docker,使用 UTS Namespace 可以實(shí)現(xiàn)在容器內(nèi)的主機(jī)名稱為 lagoudocker 或者其他任意自定義主機(jī)名。
同樣我們通過一個(gè)實(shí)例來驗(yàn)證下 UTS Namespace 的作用,首先我們使用 unshare 命令來創(chuàng)建一個(gè) UTS Namespace:
[root@docker-demo ~]# unshare --uts --fork /bin/bash [root@docker-demo ~]#
創(chuàng)建好 UTS Namespace 后,當(dāng)前命令行窗口已經(jīng)處于一個(gè)獨(dú)立的 UTS Namespace 中,下面我們使用 hostname 命令(hostname 可以用來查看主機(jī)名稱)設(shè)置一下主機(jī)名:
[root@docker-demo ~]# hostname -b lagoudocker #查看更改后的主機(jī)名 [root@docker-demo ~]# hostname lagoudocker
通過上面命令的輸出,我們可以看到當(dāng)前UTS Namespace 內(nèi)的主機(jī)名已經(jīng)被修改為 lagoudocker。然后我們新打開一個(gè)命令行窗口,使用相同的命令查看一下主機(jī)的 hostname:
[root@docker-demo ~]# hostname docker-demo
可以看到主機(jī)的名稱仍然為 docker-demo,并沒有被修改。由此,可以驗(yàn)證 UTS Namespace 可以用來隔離主機(jī)名。
IPC Namespace 主要是用來隔離進(jìn)程間通信的。例如 PID Namespace 和 IPC Namespace 一起使用可以實(shí)現(xiàn)同一 IPC Namespace 內(nèi)的進(jìn)程彼此可以通信,不同 IPC Namespace 的進(jìn)程卻不能通信。
同樣我們通過一個(gè)實(shí)例來驗(yàn)證下IPC Namespace的作用,首先我們使用 unshare 命令來創(chuàng)建一個(gè) IPC Namespace:
[root@docker-demo ~]# unshare --ipc --fork /bin/bash [root@docker-demo ~]#
下面我們需要借助兩個(gè)命令來實(shí)現(xiàn)對 IPC Namespace 的驗(yàn)證。
ipcs -q 命令:用來查看系統(tǒng)間通信隊(duì)列列表。
ipcmk -Q 命令:用來創(chuàng)建系統(tǒng)間通信隊(duì)列。
我們首先使用 ipcs -q 命令查看一下當(dāng)前 IPC Namespace 下的系統(tǒng)通信隊(duì)列列表:
[root@docker-demo ~]# ipcs -q --------- 消息隊(duì)列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息
由上可以看到當(dāng)前無任何系統(tǒng)通信隊(duì)列,然后我們使用 ipcmk -Q 命令創(chuàng)建一個(gè)系統(tǒng)通信隊(duì)列:
[root@docker-demo ~]# ipcmk -Q 消息隊(duì)列 id:0
再次使用 ipcs -q 命令查看當(dāng)前 IPC Namespace 下的系統(tǒng)通信隊(duì)列列表:
[root@docker-demo ~]# ipcs -q --------- 消息隊(duì)列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息 0x91ce1a3d 0 root 644 0 0
可以看到我們已經(jīng)成功創(chuàng)建了一個(gè)系統(tǒng)通信隊(duì)列。然后我們新打開一個(gè)命令行窗口,使用ipcs -q 命令查看一下主機(jī)的系統(tǒng)通信隊(duì)列:
[root@docker-demo ~]# ipcs -q --------- 消息隊(duì)列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息
通過上面的實(shí)驗(yàn),可以發(fā)現(xiàn),在單獨(dú)的 IPC Namespace 內(nèi)創(chuàng)建的系統(tǒng)通信隊(duì)列在主機(jī)上無法看到。即 IPC Namespace 實(shí)現(xiàn)了系統(tǒng)通信隊(duì)列的隔離。
User Namespace 主要是用來隔離用戶和用戶組的。一個(gè)比較典型的應(yīng)用場景就是在主機(jī)上以非 root 用戶運(yùn)行的進(jìn)程可以在一個(gè)單獨(dú)的 User Namespace 中映射成 root 用戶。使用 User Namespace 可以實(shí)現(xiàn)進(jìn)程在容器內(nèi)擁有 root 權(quán)限,而在主機(jī)上卻只是普通用戶。User Namesapce 的創(chuàng)建是可以不使用 root 權(quán)限的,下面我們以普通用戶的身份創(chuàng)建一個(gè) User Namespace,命令如下:
# 創(chuàng)建并切換到普通用戶 [root@docker-demo ~]# su - chengzw [chengzw@docker-demo ~]$ id uid=1002(chengzw) gid=1004(chengzw) groups=1004(chengzw) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 # 創(chuàng)建 User Namespace [chengzw@docker-demo ~]$ unshare --user -r /bin/bash
然后執(zhí)行 id 命令查看一下當(dāng)前的用戶信息:
[root@docker-demo ~]# id uid=0(root) gid=0(root) 組=0(root) 環(huán)境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
通過上面的輸出可以看到我們在新的 User Namespace 內(nèi)已經(jīng)是 root 用戶了。下面我們使用只有主機(jī) root 用戶才可以執(zhí)行的 reboot 命令來驗(yàn)證一下,在當(dāng)前命令行窗口執(zhí)行 reboot 命令:
[root@docker-demo ~]# reboot Failed to open /dev/initctl: Permission denied Failed to talk to init daemon.
查看當(dāng)前 User Namespace 所在的進(jìn)程:
[root@docker-demo ~]# echo $$ 2157
在宿主機(jī)上查看該進(jìn)程對應(yīng)的用戶,可以看到實(shí)際上在宿主機(jī)上是 chengzw 用戶:
[root@docker-demo ~]# ps -ef | grep 2157 chengzw 2157 2092 0 20:41 pts/0 00:00:00 /bin/bash
可以看到,我們在新創(chuàng)建的 User Namespace 內(nèi)雖然是 root 用戶,但是并沒有權(quán)限執(zhí)行 reboot 命令。這說明在隔離的 User Namespace 中,并不能獲取到主機(jī)的 root 權(quán)限,也就是說 User Namespace 實(shí)現(xiàn)了用戶和用戶組的隔離。
Net Namespace 是用來隔離網(wǎng)絡(luò)設(shè)備、IP 地址和端口等信息的。Net Namespace 可以讓每個(gè)進(jìn)程擁有自己獨(dú)立的 IP 地址,端口和網(wǎng)卡信息。例如主機(jī) IP 地址為 192.168.1.41 ,容器內(nèi)可以設(shè)置獨(dú)立的 IP 地址為 172.16.1.2。
同樣用實(shí)例驗(yàn)證,我們首先使用 ip addr 命令查看一下主機(jī)上的網(wǎng)絡(luò)信息:
[root@docker-demo ~]$ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:50:56:9b:2d:90 brd ff:ff:ff:ff:ff:ff inet 192.168.1.41/24 brd 192.168.1.255 scope global ens192 valid_lft forever preferred_lft forever inet6 fe80::2556:f369:b4e7:fb64/64 scope link tentative dadfailed valid_lft forever preferred_lft forever inet6 fe80::6b8d:29f7:a5fe:dbee/64 scope link tentative dadfailed valid_lft forever preferred_lft forever inet6 fe80::f387:57a3:4975:d8f2/64 scope link tentative dadfailed valid_lft forever preferred_lft forever
然后我們使用以下命令創(chuàng)建一個(gè) Net Namespace:
[root@docker-demo ~]# unshare --net --fork /bin/bash
同樣的我們使用 ip addr 命令查看一下網(wǎng)絡(luò)信息:
[root@docker-demo ~]# ip addr 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
可以看到,宿主機(jī)上有 lo、ens192 等網(wǎng)絡(luò)設(shè)備,而我們新建的 Net Namespace 內(nèi)則與主機(jī)上的網(wǎng)絡(luò)設(shè)備不同。我們可以在 Net Namespace 中新增網(wǎng)卡并配置 IP:
[root@docker-demo ~]# ip link add eth0 type dummy [root@docker-demo ~]# ip addr add 172.16.1.2/24 dev [root@docker-demo ~]# ip addr 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN qlen 1000 link/ether e6:b7:92:d4:cc:ae brd ff:ff:ff:ff:ff:ff inet 172.16.1.2/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::e4b7:92ff:fed4:ccae/64 scope link valid_lft forever preferred_lft forever
首先查看宿主機(jī)的時(shí)間,目前是3月21號:
[root@docker-demo ~]# date 2021年 03月 21日 星期日 21:02:38 CST
啟動(dòng)一個(gè) centos 容器,查看時(shí)間和宿主機(jī)一致(UTC + 8 = CST):
[root@docker-demo ~]# docker exec -it centos bash [root@a695de10917d /]# date Sun Mar 21 13:02:46 UTC 2021
嘗試在容器中修改時(shí)間,提示權(quán)限不夠:
[root@a695de10917d /]# date -s 05/28 date: cannot set date: Operation not permitted
在啟動(dòng)容器的時(shí)候,加上--cap-add SYS_TIME
參數(shù),在容器內(nèi)將時(shí)間修改成3月20號:
root@docker-demo ~]# docker run -it --cap-add SYS_TIME --name centos centos /bin/bash [root@e7b61aba6222 /]# date -s 03/20 Sat Mar 20 00:00:00 UTC 2021 [root@e7b61aba6222 /]# date Sat Mar 20 00:00:01 UTC 2021 # 退出容器 [root@e7b61aba6222 /]# exit exit
在宿主機(jī)上查看時(shí)間發(fā)現(xiàn)也改成3月20號了:
[root@docker-demo ~]# date 2021年 03月 20日 星期六 08:00:07 CST
--cap-add SYS_TIME
是為了將宿主機(jī)的內(nèi)核時(shí)間掛載進(jìn)來與容器共享,因此容器時(shí)間更改了,宿主機(jī)時(shí)間也會(huì)跟著更改。
Linux 內(nèi)核從 2002 年 2.4.19 版本開始加入了 Mount Namespace,而直到內(nèi)核 3.8 版本加入了 User Namespace 才為容器提供了足夠的支持功能。
當(dāng) Docker 新建一個(gè)容器時(shí), 它會(huì)創(chuàng)建這六種 Namespace,然后將容器中的進(jìn)程加入這些 Namespace 之中,使得 Docker 容器中的進(jìn)程只能看到當(dāng)前 Namespace 中的系統(tǒng)資源。
正是由于 Docker 使用了 Linux 的這些 Namespace 技術(shù),才實(shí)現(xiàn)了 Docker 容器的隔離,可以說沒有 Namespace,就沒有 Docker 容器。
在了解了 Linux Namespace 的隔離機(jī)制后,你應(yīng)該會(huì)很自然地想到一個(gè)問題:docker exec 是怎么做到進(jìn)入容器里的呢?
實(shí)際上,Linux Namespace 創(chuàng)建的隔離空間雖然看不見摸不著,但一個(gè)進(jìn)程的 Namespace 信息在宿主機(jī)上是確確實(shí)實(shí)存在的,并且是以一個(gè)文件的方式存在。
首先創(chuàng)建一個(gè)容器:
$ docker run -p 4000:80 helloworld python app.py
通過如下指令,你可以看到當(dāng)前正在運(yùn)行的 Docker 容器的進(jìn)程號(PID)是 25686:
$ docker inspect --format '{{ .State.Pid }}' 4ddf4638572d25686
這時(shí),你可以通過查看宿主機(jī)的 proc 文件,看到這個(gè) 25686 進(jìn)程的所有 Namespace 對應(yīng)的文件:
$ ls -l /proc/25686/ns total 0 lrwxrwxrwx 1 root root 0 Aug 13 14:05 cgroup -> cgroup:[4026531835] lrwxrwxrwx 1 root root 0 Aug 13 14:05 ipc -> ipc:[4026532278] lrwxrwxrwx 1 root root 0 Aug 13 14:05 mnt -> mnt:[4026532276] lrwxrwxrwx 1 root root 0 Aug 13 14:05 net -> net:[4026532281] lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid -> pid:[4026532279] lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid_for_children -> pid:[4026532279] lrwxrwxrwx 1 root root 0 Aug 13 14:05 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Aug 13 14:05 uts -> uts:[4026532277]
可以看到,一個(gè)進(jìn)程的每種 Linux Namespace,都在它對應(yīng)的 /proc/[進(jìn)程號]/ns 下有一個(gè)對應(yīng)的虛擬文件,并且鏈接到一個(gè)真實(shí)的 Namespace 文件上。
有了這樣一個(gè)可以“hold 住”所有 Linux Namespace 的文件,我們就可以對 Namespace 做一些很有意義事情了,比如:加入到一個(gè)已經(jīng)存在的 Namespace 當(dāng)中。
這也就意味著:一個(gè)進(jìn)程,可以選擇加入到某個(gè)進(jìn)程已有的 Namespace 當(dāng)中,從而達(dá)到“進(jìn)入”這個(gè)進(jìn)程所在容器的目的,這正是 docker exec 的實(shí)現(xiàn)原理。
而這個(gè)操作所依賴的,乃是一個(gè)名叫 setns() 的 Linux 系統(tǒng)調(diào)用。它的調(diào)用方法,我可以用如下一段小程序?yàn)槟阏f明:
#define _GNU_SOURCE #include <fcntl.h> #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE);} while (0) int main(int argc, char *argv[]) { int fd; fd = open(argv[1], O_RDONLY); if (setns(fd, 0) == -1) { errExit("setns"); } execvp(argv[2], &argv[2]); errExit("execvp"); }
這段代碼功能非常簡單:它一共接收兩個(gè)參數(shù),第一個(gè)參數(shù)是 argv[1],即當(dāng)前進(jìn)程要加入的 Namespace 文件的路徑,比如 /proc/25686/ns/net;而第二個(gè)參數(shù),則是你要在這個(gè) Namespace 里運(yùn)行的進(jìn)程,比如 /bin/bash。
這段代碼的核心操作,則是通過 open() 系統(tǒng)調(diào)用打開了指定的 Namespace 文件,并把這個(gè)文件的描述符 fd 交給 setns() 使用。在 setns() 執(zhí)行后,當(dāng)前進(jìn)程就加入了這個(gè)文件對應(yīng)的 Linux Namespace 當(dāng)中了。
現(xiàn)在,你可以編譯執(zhí)行一下這個(gè)程序,加入到容器進(jìn)程(PID=25686)的 Network Namespace 中:
$ gcc -o set_ns set_ns.c $ ./set_ns /proc/25686/ns/net /bin/bash $ ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02 inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:12 errors:0 dropped:0 overruns:0 frame:0 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:976 (976.0 B) TX bytes:796 (796.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
正如上所示,當(dāng)我們執(zhí)行 ifconfig 命令查看網(wǎng)絡(luò)設(shè)備時(shí),我會(huì)發(fā)現(xiàn)能看到的網(wǎng)卡“變少”了:只有兩個(gè)。而我的宿主機(jī)則至少有四個(gè)網(wǎng)卡。這是怎么回事呢?
實(shí)際上,在 setns() 之后我看到的這兩個(gè)網(wǎng)卡,正是我在前面啟動(dòng)的 Docker 容器里的網(wǎng)卡。也就是說,我新創(chuàng)建的這個(gè) /bin/bash 進(jìn)程,由于加入了該容器進(jìn)程(PID=25686)的 Network Namepace,它看到的網(wǎng)絡(luò)設(shè)備與這個(gè)容器里是一樣的,即:/bin/bash 進(jìn)程的網(wǎng)絡(luò)設(shè)備視圖,也被修改了。
而一旦一個(gè)進(jìn)程加入到了另一個(gè) Namespace 當(dāng)中,在宿主機(jī)的 Namespace 文件上,也會(huì)有所體現(xiàn)。
在宿主機(jī)上,你可以用 ps 指令找到這個(gè) set_ns 程序執(zhí)行的 /bin/bash 進(jìn)程,其真實(shí)的 PID 是 28499:
# 在宿主機(jī)上 ps aux | grep /bin/bash root 28499 0.0 0.0 19944 3612 pts/0 S 14:15 0:00 /bin/bash
這時(shí),如果查看一下這個(gè) PID=28499 的進(jìn)程的 Namespace,你就會(huì)發(fā)現(xiàn)這樣一個(gè)事實(shí):
$ ls -l /proc/28499/ns/net lrwxrwxrwx 1 root root 0 Aug 13 14:18 /proc/28499/ns/net -> net:[4026532281] $ ls -l /proc/25686/ns/net lrwxrwxrwx 1 root root 0 Aug 13 14:05 /proc/25686/ns/net -> net:[4026532281]
在 /proc/[PID]/ns/net 目錄下,這個(gè) PID=28499 進(jìn)程,與我們前面的 Docker 容器進(jìn)程(PID=25686)指向的 Network Namespace 文件完全一樣。這說明這兩個(gè)進(jìn)程,共享了這個(gè)名叫 net:[4026532281]的 Network Namespace。
此外,Docker 還專門提供了一個(gè)參數(shù),可以讓你啟動(dòng)一個(gè)容器并“加入”到另一個(gè)容器的 Network Namespace 里,這個(gè)參數(shù)就是 -net,比如:
$ docker run -it --net container:4ddf4638572d busybox ifconfig
這樣,我們新啟動(dòng)的這個(gè)容器,就會(huì)直接加入到 ID=4ddf4638572d 的容器,也就是我們前面的創(chuàng)建的應(yīng)用容器(PID=25686)的 Network Namespace 中。所以,這里 ifconfig 返回的網(wǎng)卡信息,跟我前面那個(gè)小程序返回的結(jié)果一模一樣,你也可以嘗試一下。
而如果我指定–net=host,就意味著這個(gè)容器不會(huì)為進(jìn)程啟用 Network Namespace。這就意味著,這個(gè)容器拆除了 Network Namespace 的“隔離墻”,所以,它會(huì)和宿主機(jī)上的其他普通進(jìn)程一樣,直接共享宿主機(jī)的網(wǎng)絡(luò)棧。這就為容器直接操作和使用宿主機(jī)網(wǎng)絡(luò)提供了一個(gè)渠道。
到此,關(guān)于“Namespace的作用是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
分享題目:Namespace的作用是什么
網(wǎng)站鏈接:http://m.newbst.com/article16/jheigg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、網(wǎng)站導(dǎo)航、電子商務(wù)、品牌網(wǎng)站設(shè)計(jì)、定制開發(fā)、移動(dòng)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)