怎麼理解docker的本質是程式

weixin_33935777發表於2019-01-06

剛開始學習docker的時候,在ppt中看到,docker本質就是程式,雲裡霧裡,就稀裡糊塗,過了一段時間不用docker,連docker長啥樣都記不起來了。這就是知其然而不知其所然。

而真正能理解docker的本質是程式,必須具備的是linux的基礎知識,從基礎知識角度來進行理解,否則就是霧裡看花,糊里糊塗。

資料上大多介紹,docker的兩大關鍵技術是Namespace和cgroup,以及docker的關鍵創新映象。所以讓我們從linux基礎知識上剖析一下。

Namespace

做個試驗,依次執行如下命令:

sudo docker pull busybox
sudo docker run -it busybox /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps

解釋一下:
setp1: 命令docker pull download下來busybox,busybox是個基礎映象。
setp2: 使用docker run,加上-it引數,執行/bin/sh,建立一個互動式命令視窗(注意如果退出用Ctrl + P + Q,退出互動式視窗,這樣不會關閉容器)
setp3: 執行ps命令

魔力就在這裡了,為何我們看到這裡有兩個程式,一個是剛剛執行的PS,一個是/bin/sh,而且程式號是1,而退出到容器外,使用

ps aux | grep /bin/sh
root     18531  0.0  0.0   1296     4 ?        Ss+  17:19   0:00 /bin/sh
ubuntu   21065  0.0  0.0  13228   928 pts/4    S+   17:48   0:00 grep --color=auto /bin/sh

只能看到18531這個程式有/bin/sh,這是怎麼實現的呢?

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 

注意增加了一個CLONE_NEWPID引數,實施了一個障眼法,在這個程式裡,程式看不到所有它前面的程式,認為自己是1號程式。這就是PID namespace.

而Namespace機制還有 PID, UTS, network, user, mount, IPC,這些Namespace技術改變了容器的檢視,讓容器以為自己在一個房間裡,起到了隔離作用。

Linux Control Group

這個是什麼作用了,就是限制,容器的本質是程式,如上namespace實施了障眼法,對資源進行了隔離,但是如果這個程式把資源都消耗光了,容器就沒有什麼價值了。

在 Linux 中,Cgroups 給使用者暴露出來的操作介面是檔案系統,即它以檔案和目錄的方式組織在作業系統的 /sys/fs/cgroup 路徑下。

cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
memory on /run/lxcfs/controllers/memory type cgroup (rw,relatime,memory)
cpuset on /run/lxcfs/controllers/cpuset type cgroup (rw,relatime,cpuset)
freezer on /run/lxcfs/controllers/freezer type cgroup (rw,relatime,freezer)
blkio on /run/lxcfs/controllers/blkio type cgroup (rw,relatime,blkio)
hugetlb on /run/lxcfs/controllers/hugetlb type cgroup (rw,relatime,hugetlb)
pids on /run/lxcfs/controllers/pids type cgroup (rw,relatime,pids)
devices on /run/lxcfs/controllers/devices type cgroup (rw,relatime,devices)
cpu,cpuacct on /run/lxcfs/controllers/cpu,cpuacct type cgroup (rw,relatime,cpu,cpuacct)
net_cls,net_prio on /run/lxcfs/controllers/net_cls,net_prio type cgroup (rw,relatime,net_cls,net_prio)
perf_event on /run/lxcfs/controllers/perf_event type cgroup (rw,relatime,perf_event)
name=systemd on /run/lxcfs/controllers/name=systemd type cgroup (rw,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)

可以看到可以限制cpu、記憶體等各類資源。
如果執行

docker run -it --cpu-period=100000 --cpu-quota=20000 busybox /bin/sh

如果檢視 /sys/fs/cgroup/cpu/cpu.cfs_quota_us,會看到20000被寫入到了檔案中,這樣20000/100000,說明寫入到tasks中的程式智慧佔用20%的CPU。這就是限制作用的原理。

namespace和cgroup共同為創造了一個容器沙盒。

容器映象

容器映象不同於虛擬機器映象,虛擬機器映象一般是硬碟的拷貝,非常大,但是容器映象就沒有那麼大,怎麼做的呢?

容器是使用層結構的映象,至少有三層,從上到下依次為:

  • 讀寫層
  • init層
  • 只讀層

(1) 只讀層
是什麼東西呢,只讀層就是基礎映象,做個試驗:

/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

在namespace試驗中busybox映象中執行ls,可以看到就是一個linux作業系統的系統檔案,而且是精簡版的。這些檔案從哪裡來,從busybox中,按照namespace技術,被mount到容器根目錄下,檢查這裡面的檔案,和容器外的檔案中的內容還是有很大區別。

只讀層的這個映象我們可以在/var/lib/docker/overlay2下可以找到,可以證明上述mount namespace。

(2) init層
初始化的環境變數

(3) 讀寫層
讀寫層就是我們編寫的程式,這些程式會覆蓋下層的檔案

這就是容器映象的方式,由於容器映象可以打包作業系統的檔案,相當於大了原生的系統檔案,所以具備了一致效能力,即打包後隨處下載,都是一樣的。

小結

通過深入linux基礎知識的學習後,我們看到了容器是怎樣的一個存在,是個程式,通過namespace作為障眼法進行遮蔽,通過cgroup進行資源限制,通過容器映象的方式打包的一個沙盒。因此容器的本質就是映象。
對比一下虛擬機器,虛擬機器是虛擬出硬體來,安裝上獨立的作業系統,因此本質上和docker有絕對的不同。

相關文章