<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我使用了 docker exec
命令進入到了容器當中。在瞭解了Linux Namespace
的隔離機制後,你應該會很自然地想到一個問題:docker exec 是怎麼做到進入容器裡的呢?
實際上,Linux Namespace
建立的隔離空間雖然看不見摸不著,但一個程序的 Namespace
資訊在宿主機上是確確實實存在的,並且是以一個檔案的方式存在。
比如,通過如下指令,你可以看到當前正在執行的 Docker 容器的程序號(PID)是 25686:
$ docker inspect --format '{{ .State.Pid }}' 4ddf4638572d 25686
這時,你可以通過檢視宿主機的 proc 檔案,看到這個 25686 程序的所有 Namespace 對應的檔案:
$ 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]
可以看到,一個程序的每種Linux Namespace
,都在它對應的 /proc/[程序號]/ns 下有一個對應的虛擬檔案,並且連結到一個真實的 Namespace 檔案上。
有了這樣一個可以“hold 住”所有 Linux Namespace 的檔案,我們就可以對 Namespace 做一些很有意義事情了,比如:加入到一個已經存在的 Namespace 當中。
這也就意味著:一個程序,可以選擇加入到某個程序已有的 Namespace 當中,從而達到“進入”這個程序所在容器的目的,這正是 docker exec 的實現原理。
而這個操作所依賴的,乃是一個名叫 setns() 的 Linux 系統呼叫。它的呼叫方法,我可以用如下一段小程式為你說明:
#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"); }
這段程式碼功能非常簡單:它一共接收兩個引數,第一個引數是 argv[1],即當前程序要加入的 Namespace 檔案的路徑,比如/proc/25686/ns/net
;而第二個引數,則是你要在這個 Namespace
裡執行的程序,比如 /bin/bash。
這段程式碼的的核心操作,則是通過 open() 系統呼叫開啟了指定的 Namespace
檔案,並把這個檔案的描述符 fd 交給 setns() 使用。在 setns() 執行後,當前程序就加入了這個檔案對應的 Linux Namespace
當中了。
現在,你可以編譯執行一下這個程式,加入到容器程序(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)
正如上所示,當我們執行 ifconfig
命令檢視網路裝置時,我會發現能看到的網路卡“變少”了:只有兩個。而我的宿主機則至少有四個網路卡。這是怎麼回事呢?
實際上,在 setns() 之後我看到的這兩個網路卡,正是我在前面啟動的 Docker 容器裡的網路卡。也就是說,我新建立的這個 /bin/bash 程序,由於加入了該容器程序(PID=25686)的 Network Namepace,它看到的網路裝置與這個容器裡是一樣的,即:/bin/bash 程序的網路裝置檢視,也被修改了。
而一旦一個程序加入到了另一個 Namespace 當中,在宿主機的 Namespace 檔案上,也會有所體現。
在宿主機上,你可以用 ps 指令找到這個 set_ns 程式執行的 /bin/bash 程序,其真實的 PID 是 28499:
# 在宿主機上 ps aux | grep /bin/bash root 28499 0.0 0.0 19944 3612 pts/0 S 14:15 0:00 /bin/bash
這時,如果按照前面介紹過的方法,檢視一下這個 PID=28499 的程序的 Namespace,你就會發現這樣一個事實:
$ 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
目錄下,這個 PID=28499 程序,與我們前面的 Docker 容器程序(PID=25686)指向的 Network Namespace
檔案完全一樣。這說明這兩個程序,共用了這個名叫net:[4026532281] 的 Network
Namespace。
此外,Docker 還專門提供了一個引數,可以讓你啟動一個容器並“加入”到另一個容器的 Network Namespace 裡,這個引數就是 -net,比如:
$ docker run -it --net container:4ddf4638572d busybox ifconfig
這樣,我們新啟動的這個容器,就會直接加入到 ID=4ddf4638572d
的容器,也就是我們前面的建立的應用容器(PID=25686)的Network Namespace
中。所以,這裡 ifconfig 返回的網路卡資訊,跟我前面那個小程式返回的結果一模一樣,你也可以嘗試一下。
而如果我指定–net=host,就意味著這個容器不會為程序啟用 Network Namespace
。這就意味著,這個容器拆除了 Network Namespace
的“隔離牆”,所以,它會和宿主機上的其他普通程序一樣,直接共用宿主機的網路棧。這就為容器直接操作和使用宿主機網路提供了一個渠道。
到此這篇關於Docker exec 的實現原理介紹的文章就介紹到這了,更多相關Docker exec 的實現內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45