乾貨 | Docker文件系統的分層與隔離
現在就開始今天的分享~
M老師:docker 的很多特性都表現在它所使用的文件系統上,比如大家都知道docker的文件系統是分層的,所以它可以快速迭代,可以回滾。這個回滾機制跟github很像,每次提交的時候都會有一個id, 回滾就是跟據這個id來操作的。
M老師:docker所支持的文件系統有以下幾種:Aufs、devicemapper、btrfs和Vfs,其中前三種是聯合文件系統,可以支持分層,VFS 不支持。平時用的最多的是aufs 和devicemapper。
M老師:先介紹一下Aufs,Aufs(advanced multi layered unification filesystem), 直譯過來就是高級分層聯合文件系統,做為一種Union FS ,它支持將不同的目錄掛載到同一個虛擬文件系統下。
M老師:這個怎麼理解呢,通過一條命令我們來看一下:
mount -t aufs -o br=/tmp/dir1=ro:/tmp/dir2=rw none /tmp/newfs
M老師:大家有條件的可以一起做下實驗,方便理解,-o 指定mount傳遞給文件系統的參數;br 指定需要掛載的文件夾,這裡包括dir1和dir2;ro/rw 指定文件的許可權只讀和可讀寫;none 這裡是掛載的設備,而沒有設備用none表示。
M老師:為什麼要有隻讀和可讀寫兩種呢,因為docker在啟動容器的時候就會用到這兩種,而上面這個例子是模擬這個docker文件系統模型。
問:啟動docker的時候,對硬碟使用只讀,意義在於什麼?
答:這個問題很好,一個image可以啟動多個container,這時候會有一個問題,如果每個container對大家共有的部分都有可寫的許可權,就會出問題。所以docker啟動的時候會載入鏡像的文件系統那層是只讀的,然後每個contianer 獲取自己的可讀寫的層,如果container要修改只讀層的文件,那麼該文件就會從只讀層提取到讀寫層。只讀層的文件就被讀寫層的文件覆蓋了,但只讀層的那個文件依然存在 這個就實現了文件系統上的隔離。
問:就像我們寫程序抵觸共享的東西不變,只是利用這個共性來底層共享?
答:是的。
問:加那個none是幹什麼用的?
答:none 這裡沒有設備,用none表示,其實是沒有意義的。但命令要求要有一個設備,這條命令中設備是none
問:這個命令是在容器里執行的嗎?還是在宿主機?
答:容器。
M老師:繼續咱們的分享,剛才實驗的結果是什麼樣子呢,就是把/tmp/dir1和/tmp/dir2 合併之後掛載到/tmp/newfs,如果這時在/tmp/dir1 下創建一個文件a,/tmp/dir2下創建一個文件b 則 在/tmp/newfs 會看到a,b 這兩個文件,這就是聯合,並且a文件是只讀的。
M老師:如果有相同的文件則以先掛載的為準,後面掛載的操作會被忽略掉。大家可以想像一下,我每做一次操作都相當於去掛載一個新的目錄,這樣所有的操作就保存下來了。當然實際情況並不是每次操作都去掛載。當container 發生改變的時候,並且我提交commit 才會重新掛載一層。
問:比如mkdir test 這也算是重新掛載了一層?
答:docker有一個命令docker commit,執行這個的時候會重新掛載一層。
M老師: 可能還會有一些不理解,下面用實際的docker 鏡像來舉個例子。大家啟動一個container 之後,執行 docker save,可以把container保存成鏡像。
例如:
docker save
cloud_jiankongbao:01.tar
cloud_jiankongbao:01
其中cloud_jiankongbao:01.tar是鏡像的名字,後面的cloud_jiankongbao:01是這個container的ID,可以看到,保存下來的是tar 包。 不是.iso文件^_^
M老師:鏡像解壓之後是什麼呢,我們來看一下:
ls .
a005304e4e74c1541988d3d1abb170e338c1d45daee7151f8e82f8460634d329
d9bde94c518a16a886514758b6b4431200145ecd58e30c5633ac3c0256544d77
f1b10cd842498c23d206ee0cbeaa9de8d2ae09ff3c7af2723a9e337a6965d639
fb9cc58bde0c0a8fe53e6fdd23898e45041783f2d7869d939d7364f5777fde6f
裡面有四個目錄,其實分別是4個docker的ID,每次使用docker commit 提交對docker的修改之後就會產生一個新的id,就是通過這個ID實現對鏡像的回滾。
M老師:這4個目錄之間是有關係的。這個關係可以通過docker image --tree 來查看。
docker images --tree
└─f1b10cd84249 Virtual Size: 0 B
└─fb9cc58bde0c Virtual Size: 203.1 MB
└─a005304e4e74 Virtual Size: 203.1 MB
└─d9bde94c518a Virtual Size: 1.957 GB Tags: cloud_jiankongbao:01
M老師:每個目錄下有json layer.tar VERSION 這三個文件,我們現在只研究他們的結構,所以只看layer.tar 這個文件。
M老師:我們到一個目錄下把layer.tar 解壓一下
dfb9cc58bde0c0a8fe53e6fdd23898e45041783f2d7869d939d7364f5777fde6f;tar -xflayer.tar;ls
ls fb9cc58bde0c0a8fe53e6fdd23898e45041783f2d7869d939d7364f5777fde6f/
binetcjsonliblost+foundmntprocsbinsrvtmpvar
devhomelayer.tar lib64 mediaopt root selinux sys usr VERSION
問:為什麼會提交四次?
答:提交4次是我們自己提交的.
M老師:在使用docker的過程中我們需要保存自己的修改,docker commit 執行完之後就把container中的內容回寫到鏡像中了,就相當於加了一層文件系統,每次提交後就生成了一個新的鏡像。4個ID是4次提交的鏡像的ID,這4個ID 其實相當於一個鏡像的4個tag。我們再看一下4個鏡像ID的系統:
f1b10cd84249 這個鏡像是初始鏡像,大小為0
fb9cc58bde0c 這個鏡像是在f1b10cd84249基礎上創建新的鏡像;
a005304e4e74是以fb9cc58bde0c為基礎創建新的鏡像,是樹狀繼承的關係;
M老師:我們再看一下不同ID目錄下的bin 目錄。
ls a005304e4e74c1541988d3d1abb170e338c1d45daee7151f8e82f8460634d329/bin/
gtar tar
a005304e4e74隻有兩個文件,fb9cc58bde0c包括了大部分bin下的文件,對應的場景是 fb9cc58bde0c,是裝好操作系統, 然後我又裝了tar這個工具。docker commit提交之後,就是a005304e4e。
問:可以認為fb9cc58bde0c是一個最小化的OS
答:可以這麼理解。
M老師:最後簡單說一下devicemapper,回到最開始說的,docker支持多種文件系統。devicemapper是利用了Snapshot 和Thinly-Provisioned Snapshot兩種原理,將多個快照掛在同一個卷下從而實現文件系統的分層。這裡的快照技術其實就是vm中的快照。
M老師:剛才說的autofs 是將不同的目錄掛到一個虛擬目錄,devicemapper 就是把多個快照掛載到同一個卷下,不過使用devicemapper 的話,一個container的大小最大只能是10G,啟動docker daemon時用參數-s 指定:
docker -d -s devicemapper
M老師:當容器基於鏡像啟動之後,每個容器都會獲得自己的寫讀可寫的文件系統層。原鏡像的那部分文件系統是只讀的,從而實現每個容器的在文件系統上的隔離。
問:autofs 最大一個container是多大?
答:沒有限制,直到物理伺服器沒有資源,但通常不會將資料庫和LOG保存在鏡像中,所以也不會寫的太大,因為docker本身是輕量級的。
M老師:平時大家都在說dokcer 是弱隔離的,因為他沒有隔離的很徹底,比如內核是跟大家共用的,跟宿主機共用同一個內核。SELinux、 Cgroups以及/sys、/proc/sys、/dev/sd*等目錄下的資源是與宿主機共用的。如果要隔離的徹底那就是VM了,而且如果dockers要想實現這些隔離就必然要犧牲一下現在輕量級的特性。
M老師:好吧,今天的分享就到這裡了,謝謝大家!
推薦閱讀:
TAG:Docker |