透過對 namespace 的討論,我們知道了所謂的「隔離」,其實就是建立各種不同種類的命名空間給我們要新執行的那個 process,如此一來這個 process 及其後續建立出來的 processes 就只能看到這些新命名空間中的資訊,看不到 parent namespace,也看不到其他 namespace 裡的資料。
container 就是用了這樣 namespace 的技術去達成隔離的,更直接地說,這些在 container 中的 processes 是「被騙」了,他們的的視圖被這些命名空間們給限制住了,所以看不到其他人,以至於覺得這個世界只有我,殊不知,從 Host 的視角來說,根本是裸體的、一覽無遺的,還記得我們在 Day 03 做的實驗嗎?在 container 中的 process 中其實在 Host 中都看得到,也有自己的 PID,我們來多做幾個試試看:
$ docker run -it alpine ash
/ # sleep 2000 &
/ # ps -eaf
PID USER TIME COMMAND
1 root 0:00 ash
7 root 0:00 sleep 2000
8 root 0:00 ps -eaf
用另外一個 terminal 查看一下 Host 中的情況:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ffb4953e6750 alpine "ash" 6 minutes ago Up 6 minutes fervent_albattani
$ docker container inspect --format='{{ json .State }}' ffb4953e6750 | jq
{
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 58127,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-09-29T14:13:05.026420935Z",
"FinishedAt": "0001-01-01T00:00:00Z"
}
$ ps -eaf
...略
root 58127 58107 0 14:13 pts/0 00:00:00 ash
root 58155 58127 0 14:13 pts/0 00:00:00 sleep 2000
在 Host 中是可以看得到在 container 中的 ash
以及 sleep 2000
的。我們之前說過,container 其實就只是 Host 中的 process 而已,但他比較特殊,特殊在哪裡呢?就是在這裡,container 中的 processes 被騙了,以為全世界只有他們,但其實並不是,是不是很可憐呢?(喂)
在繼續下去之前,先帶大家看一個目錄 /proc/58127/ns
:
$ sudo ls -al /proc/58127/ns
total 0
dr-x--x--x 2 root root 0 Sep 29 14:13 .
dr-xr-xr-x 9 root root 0 Sep 29 14:13 ..
lrwxrwxrwx 1 root root 0 Sep 29 14:21 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 ipc -> 'ipc:[4026532278]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 mnt -> 'mnt:[4026532276]'
lrwxrwxrwx 1 root root 0 Sep 29 14:13 net -> 'net:[4026532280]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 pid -> 'pid:[4026532279]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 pid_for_children -> 'pid:[4026532279]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Sep 29 14:21 uts -> 'uts:[4026532277]'
/proc/[PID]/ns
這個目錄裡儲存了這個 process 所在的各種 namespaces 的 file descriptor,在 Linux 的世界裡,所有的東西都是一個 file,file descriptor 則是一個用來辨識某一個 open file 的唯一編號。
這時候如果我們在 container 中用 lsns
查看 namespace,會看到以下結果:
# alpine 中沒有 lsns 指令,安裝一下:
/ # apk add util-linux
...略
/ # lsns
NS TYPE NPROCS PID USER COMMAND
4026531834 time 3 1 root ash
4026531835 cgroup 3 1 root ash
4026531837 user 3 1 root ash
4026532276 mnt 3 1 root ash
4026532277 uts 3 1 root ash
4026532278 ipc 3 1 root ash
4026532279 pid 3 1 root ash
4026532280 net 3 1 root ash
是不是跟 /proc/58127/ns
裡的檔案結果一致呢?
這個 container 中還有另外一個 process 是 sleep 2000
,透過在 Host 用 ps
指令查看,我們可以知道他的 PID 是 58155,那我們也來看一下 /proc/58155/ns
的內容:
# 回到 Host
$ sudo ls -al /proc/58155/ns
total 0
dr-x--x--x 2 root root 0 Sep 29 14:29 .
dr-xr-xr-x 9 root root 0 Sep 29 14:14 ..
lrwxrwxrwx 1 root root 0 Sep 29 14:41 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 ipc -> 'ipc:[4026532278]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 mnt -> 'mnt:[4026532276]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 net -> 'net:[4026532280]'
lrwxrwxrwx 1 root root 0 Sep 29 14:29 pid -> 'pid:[4026532279]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 pid_for_children -> 'pid:[4026532279]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Sep 29 14:41 uts -> 'uts:[4026532277]'
是不是跟 /proc/58127/ns
裡頭的都一模一樣呢,也就是在 container 裡的兩個 processes,他們所在的各種 namespaces 都是一樣的。
讓我們在 Host 隨意啟動一個 process,並且去觀察一下他的 ns 是什麼:
$ sleep 3000 &
[1] 58326
$ sudo ls -al /proc/58326/ns
total 0
dr-x--x--x 2 ubuntu ubuntu 0 Sep 29 14:43 .
dr-xr-xr-x 9 ubuntu ubuntu 0 Sep 29 14:43 ..
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 mnt -> 'mnt:[4026531841]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 net -> 'net:[4026531840]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 time -> 'time:[4026531834]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 user -> 'user:[4026531837]'
lrwxrwxrwx 1 ubuntu ubuntu 0 Sep 29 14:43 uts -> 'uts:[4026531838]'
$ sudo lsns -t pid
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 122 1 root /sbin/init
4026532279 pid 2 58127 root ash
可以看到跟 container 裡的 processes 的 namespaces 都不一樣。透過在 Host 執行 lsns
,也可以查看到目前有兩個 PID namespaces,4026531836
恰好是 PID 58326 這個 process 的 PID namespace,而 4026532279
則會是 container 中的那兩個 processes 的 PID namespace。
親眼「看到」這些 namespaces 是不是很有趣呢?有沒有一種 container 愈來愈不神秘的感覺?