容器技術的核心
所謂容器,其實是由Linux Namespace、Linux Cgroups和rootfs三種技術構建出來的進程的隔離環境
對於Docker項目來說,其實最核心就是為待創建的用戶進程:
- 啟動Linux Namespace配置
- 設置指定的Cgroups參數
- 切換進程的根目錄(Change Root)
1. Namespace機制
PID Namespace實現創建(clone)出來的進程,認為自己的當前容器里PID為1的進程,看不到宿主機的真正的進程,也看不到其他PID的具體情況
Mount Namespcace實現被隔離的進程只能看到當前Namespace的掛載點信息
Network Namespace實現讓被隔離進程看到當前Namespace的網絡設備和配置
Linux提供了UTS、IPC、User的Namespace
總結 :Namespce技術修改了應用進程看待整個計算機的“視圖”,只能看到某些指定的內容
Namespace隔離機制的不足:
多個容器使用的是同一個宿主機的操作系統內核,windowns上運行Linux容器,或者在低版本的Linux宿主機上運行高版本的Linux容器,是不行的
2. Cgroups
雖然進程被隔離起來了,但是它所能使用的資源,比如CPU、內存,是可以被宿主機上的其他進程占用的,也可以將所有的資源耗盡,而Cgroups解決了這個問題
Cgroups全稱是Linux Control Group,主要作用就是限制一個進程能夠使用的資源上限,包括CPU、內存、磁盤、網絡帶寬等。
Cgroups的缺點:
/proc文件不知道用戶通過Cgroups給容器做了什么資源限制,所以當我們在容器里執行top命令的時候,看到的其實是宿主機的CPU和內存數據
3. rootfs
容器的根目錄通常會掛載一個完整的文件系統,在容器啟動后就可以用ls /查看根目錄所有的內容,
這個掛載在容器根目錄,為容器提供隔離后執行環境的文件系統,就是rootfs(容器鏡像),
容器鏡像中,通過會包括如下目錄和文件
bin dev etc home lib lib64 mnt opt proc root run sbin sys tmp usr var
rootfs只是一個操作系統的所有文件和目錄,並不包含內核,通過Mount Namespace和rootfs,可以構建出一個完善的文件系統隔離環境,其中使用了chroot和pivot_root兩個系統調用切換進程根目錄的能力。
在mount namespace被創建后,父進程會把自己的文件結構復制給子進程,而子進程中新的namespace所有的mount操作都只影響自身的文件系統,不對外界產生任何影響。
每次修改rootfs,新的rootfs和舊的就不同了,Docker公司為了解決rootfs的增量修改的功能,創新的提出了層的概念
容器中的層的概念
在rootfs的基礎上,Docker公司創新的使用了多個增量rootfs聯合掛載一個完整rootfs的方案
例如,C目錄是由A和B掛載得到,擁有A和B的所有文件
層分為三種,如下圖
1.只讀層
位於rootfs最下面,掛載方式是只讀,這些層以增量的方式分別包含了操作系統的一部分
2.可讀寫層
掛載方式為rw,比如,當刪除只讀的一個xx文件時,這個刪除操作實際只是在可讀寫層創建了一個名叫.wh.xx的文件,當兩個層聯合掛載后,xx文件會被.wh.xx文件遮擋,相當於“消失了”
在容器中修改文件時,Docker會從上到下在各鏡像層中查找文件。找到后會把此文件復制到容器層(可讀寫層),這就是Copy on Write
3. init層
以一個-init結尾的層,在只讀和讀寫層之間,用來存放/etc/hosts、/etc/resolve.conf等信息,這此文件本來是屬於操作系統層的一部分,但是用戶往往需要在運行時指定hostname,所以就需要在可讀寫層修改,這些修改往往保對當前容器有效,我們並不想在docker commit的時候,把這些和讀寫層一起提交,於是就有了這一層