image 的部份我們先暫時告一個段落,其實還有一些蠻值得討論的地方,但先讓我們跳開一下,回到我們在 Day 03 中提出的疑問,當時我們用 image alpine
啟動了一個 container,並且觀察到在 container 中執行 ps aux
時,只會看到兩個 process 被列出來,且 ash
會是 PID 為 1 的 process,而在 Host 中,他的 PID 其實是 1655。當時我們提出了兩個問題:
第一個問題透過 image 的討論,我們已經知道 ash 這個指令是由 alpine
這個 image 提供的。那第二個問題呢?
關於第二個問題,我們就必須要從 container 的核心技術開始討論起,相信接觸過 docker 或 container 的人,或多或少聽說過實現 container 的兩大核心技術是 namespace 與 cgroups,namespace 是用來做隔離的,cgroups 則是用來達成資源限制的。而這兩項技術都是 linux 上的,也因此 container 是一個在 linux 上被實現的技術,這也是為什麼在 Day 02 準備實驗環境時,會建議大家盡可能用 linux 作業系統來做實驗的原因。那到底什麼是 namespace 與 cgroups 呢?這兩個就是我接下來想要試著學習的方向了。
首先,讓我們先來討論看看什麼是 namespace,根據 wiki 裡的定義是:
Namespaces are a feature of the Linux kernel that partitions kernel resources such that one set of processes sees one set of resources while another set of processes sees a different set of resources.
另外也可以看一下 Linux manual page 中提到的:
A namespace wraps a global system resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of the global resource. Changes to the global resource are visible to other processes that are members of the namespace, but are invisible to other processes. One use of namespaces is to implement containers.
透過上面兩段描述,我們大概可以知道 namespace 是將 global 的系統資源封裝起來,讓在這個 namespace 中的 processes 可以看到這些資源,但在其他 namespace 中的 processes 則看不到,也正因為不同的 namespace 下的 processes 看到的資源不同,讓這些不同組的 processes 之間看起來像是彼此「隔離」了。
在 Linux manual page 也列出了在 linux 上的 namespace 類別:
可以看到其中一個 namespace 是 PID
,恰好跟我們觀察到、想要討論的問題有關,那我們就從 PID namespace 開始實驗看看吧,如同之前對於 OverlayFS 的實驗一樣,我們會先跳開 docker container 的討論,試著先從 linux 來討論起。
在 Linux manual page 中有列出 namespace 相關的 API,其中有一個 unshare
引起了我的注意,我另外去查了他的 man page,發現他是一個可以讓程式跑在一個新的 namespace 的指令,所以就用 unshare
這個指令來試試看吧!
在開始前,讓我們先用 lsns
這個指令查看一下目前的有哪些 PID namespaces:
$ sudo lsns -t pid
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 118 1 root /sbin/init
可以看到目前我的 Host 中有一個 PID namespace,且其 namespace identifier 為 4026531836
(即為 NS 欄位)。要注意一下,我的 Host 中目前沒有任何在執行中的 containers,如果你目前有一些正在執行中的 containers,看到的結果會不一樣喔。
讓我們用 unshare 建立一個新的 pid namespace,並且 fork /bin/bash
這個 process 在這個新建立的 PID namespace 中:
ubuntu@ip-xxx:~$ sudo unshare --pid --fork --mount-proc /bin/bash
root@ip-xxx:/home/ubuntu#
可以看到使用者被切換成 root
了,用 ps 觀察一下:
root@ip-xxx:/home/ubuntu# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:35 pts/1 00:00:00 /bin/bash
root 11 1 0 15:36 pts/1 00:00:00 ps -ef
欸,是不是跟我們用 alpine
image 啟動 container 後,在那個 container 中看到的東西很像呢?只有兩個 processes,且 /bin/bash
的 PID 為 1。
在這個新的 namespace 中執行 lsns 看看:
root@ip-xxx:/home/ubuntu# lsns -t pid
NS TYPE NPROCS PID USER COMMAND
4026532207 pid 2 1 root /bin/bash
用另外一個 terminal 連線至 Host,也用 lsns
查看一下:
$ sudo lsns -t pid
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 111 1 root /sbin/init
4026532207 pid 1 42009 root /bin/bash
除了原本的 4026531836 這個 namespace 之外,還多了一個新的 namespace,其 namespace identifier 為 4026532207。
到目前為止,有沒有覺得愈來愈接近 container 的核心技術了呢?由於時間的關係,剩下的部分,就留給明天繼續啦~