本節書摘來自華章社群《docker進階與實戰》一書中的第3章,第3.4節docker image擴充知識,作者華為docker實踐小組,更多章節内容可以通路雲栖社群“華章社群”公衆号檢視
3.4 docker image擴充知識
cgroup和namespace等容器相關技術已經存在很久,在vps、paas等領域也有很廣泛的應用,但是直到docker的出現才真正把這些技術帶入到大衆的視野。同樣,docker的出現才讓我們發現原來可以這樣管理鏡像,可以這樣糅合老技術以适應新的需求。docker引入聯合挂載技術(union mount)使鏡像分層成為可能;而git式的管理方式,使基礎鏡像的重用成為可能。現在就了解一下相關的技術吧。
3.4.1 聯合挂載
聯合檔案系統這種思想由來已久,這類檔案系統會把多個目錄(可能對應不同的檔案系統)挂載到同一個目錄,對外呈現這些目錄的聯合。1993年werner almsberger實作的“inheriting file system”可以看作是一個開端。但是該項目最終廢棄了,而後其他開發者又為linux社群貢獻了unionfs(2003年)、 aufs(2006年) 和union mounts(2004年),但都因種種原因未合入社群。直到overlayfs在2014年合入linux主線,才結束了linux主線中無聯合檔案系統的曆史。
這種聯合檔案系統早期是用在livecd領域。在一些發行版中我們可以使用livecd快速地引導一個系統去初始化或檢測磁盤等硬體資源。之是以速度很快,是因為我們不需要把cd中的資訊拷貝到磁盤或記憶體等可讀可寫的媒體中。而隻需把cd隻讀挂載到特定目錄,然後在其上附加一層可讀可寫的檔案層,任何導緻檔案變動的修改都會被添加到新的檔案層内。這就是寫時複制(copy-on-write)的概念。
3.4.2 寫時複制
寫時複制是docker image之是以如此強大的一個重要原因。寫時複制在作業系統領域有很廣泛的應用,fork就是一個經典的例子。當父程序fork子程序時,核心并沒有為子程序配置設定記憶體(當然基本的程序控制塊、堆棧還是需要的),而是讓父子程序共享記憶體。當兩者之一修改共享記憶體時,會觸發一次缺頁異常導緻真正的記憶體配置設定。這樣做既加速了子程序的建立速度,又減少了記憶體的消耗(如圖3-4所示)。

docker image使用寫時複制也是為了達到相同目的:快和節省空間。我們以核心主線中的overlayfs作為例子介紹一下寫時複制。
overlayfs會把一個“上層”的目錄和“下層”的目錄組合在一起:“上層”目錄和“下層”目錄或者組合,或者覆寫,或者一塊呈現。當然“下層”目錄也可以是聯合檔案系統的挂載點。
首先你需要有支援overlayfs 的linux環境(核心3.18以上)。ubuntu使用者可以從ubuntu維護的kernel版本中下載下傳最新的核心安裝包(比如vivid版本)。當然也可以手工編譯新版的kernel,但這不是本文的重點,是以暫不細說。下面的測試為了突出變化,删除了無用的檔案。
1.覆寫
現在,在merge目錄中可以看到混凝土、鋼筋和大理石了。并且混凝土是合格的,也就是說material2目錄中的concrete覆寫了material目錄的對應檔案。是以目錄所處的層級是很重要的,上層的檔案會覆寫同名的下層檔案;另外現在的檔案系統中會儲存兩份混凝土資料,是以不合理地修改一個大檔案會使image的size大增。示例如下:
2.新增
接下來要在merge目錄下建立我們的建築架構,此時可以看到frame檔案出現在了build目錄中。示例如下:
3.删除
如果此時客戶又提出了新的需求,他們不希望使用大理石地闆了,那麼我們就得在merge目錄删掉大理石。可以看到删除底層檔案系統中的檔案或目錄時,會在上層建立一個同名的主次裝置号都為0的字元裝置,但并沒有直接删掉marble檔案。是以删除并不一定能減小image的大小,并且要注意的是,如果制作image時使用到了一些關鍵的資訊(使用者名、密碼等),則需要在同層删除,不然這些資訊依然會存在于image中。
聯合檔案系統是實作寫時複制的基礎。現在社群和作業系統廠家都維護着幾種該類檔案系統,比如ubuntu系統自帶aufs的支援,redhat和suse則采用的是devicemapper方案等。一些檔案系統比如btrfs也具有寫時複制的能力,故也可以作為docker的存儲驅動。這些存儲驅動的存儲結構和性能都有顯著的差異,是以我們需要根據實際情況選用合理的後端存儲驅動。
3.4.3 git式管理
git是由linux之父linus torvalds創立的一個開源項目,是一種代碼的分布式版本控制工具。因其具有強大的分支能力、便于協作開發等優點而取得了空前的成功,github.com作為托管代碼的倉庫也變得越來越流行。兩者的合力直接變革了傳統的軟體托管方案。
docker作為新的開源項目,充分借鑒了git的優點(利用分層)來管理鏡像,使image layer的複用變成了可能,并且類比github提出了dockerhub的概念,一定程度上變革了軟體釋出流程。