Docker 對 container 的使用基本是建立在 LXC 基礎之上,然而 LXC 存在的問題是難以移動,難以通過標准化的模板去制作、重建、復制和移動 container。
在以 VM 為基礎的虛擬化中,有 image 和 snapshot 可以用於 VM 的復制、重建以及移動的功能。
想要通過 container 來實現快速的大規模部署和更新,這些功能不可或缺。
在 Docker 0.7 中引入了 Storage Driver(儲存驅動), 現在已經支持 AUFS、Btrfs、Device Mapper、OverlayFS、ZFS、VFS。
一、儲存驅動
https://docs.docker.com/storage/storagedriver/select-storage-driver/
1.Union FileSystem
簡稱 Union FS(聯合文件系統),儲存驅動的一種。
一種分層、輕量級並且高性能的文件系統,它支持對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下。
特性:一次同時加載多個文件系統,但從外面看起來,只能看到一個文件系統,聯合加載會把各層文件系統疊加起來,這樣最終的文件系統會包含所有底層的文件和目錄。
2.Overlay2
Overlay2 是一種 Union FS,支持為每一個成員目錄(AKA branch)設定 readonly、readwrite 和 whiteout-able 權限。
通常 Union FS 有兩個用途:
- 不借助 LVM, RAID 將多個 disk 和掛載到一個目錄下。
- 將一個 readonly 的 branch 和一個 writeable 的 branch 聯合在一起,Live CD 正是基於此,可以允許在 OS image 不變的基礎上允許用戶在其上進行一些寫操作。
Docker 在 Overlay2 上構建的 container image 也正是如此。
OverlayFS 將單個 Linux 主機上的兩個目錄分層,並將它們顯示為單個目錄。這些目錄稱為層,統一過程稱為聯合安裝。
Overlay2 原生支持多達 128 OverlayFS 層。
下圖顯示了 Docker鏡像 和 Docker容器 的分層方式。圖像層是 lowerdir,容器層是 upperdir。統一視圖通過一個被稱為 merged 容器掛載點的目錄公開。
二、Linux 系統啟動
典型的 Linux 啟動到運行需要兩個FS - bootfs + rootfs (從功能角度而非文件系統角度)
bootfs(boot file system):
主要包含 bootloader 和 kernel,bootloader 主要是引導加載 kernel,當 kernel 被加載到內存中后,bootfs 就被 umount 了,此時內存的使用權已由 bootfs 轉交給 kernel。
rootfs (root file system) :
在 bootfs 之上。包含的就是典型 Linux 系統中的 /dev、/proc、/bin、/etc 等標准目錄和文件。
由此可見對於不同的 linux 發行版,bootfs 基本是一致的,rootfs 會有差別,,因此不同的發行版可以公用 bootfs。如下圖:
三、Docker image 結構
典型的 Linux 在啟動后,首先將 rootfs 置為 readonly,進行一系列檢查, 然后將其切換為 "readwrite" 供用戶使用。
在 Docker 中,起初也是將 rootfs 以 readonly 方式加載並檢查,然而接下來利用 union mount 將一個 readwrite 文件系統掛載在 readonly 的 rootfs 之上,並且允許再次將下層的 file system 設定為 readonly,並且向上疊加。
這樣一組 readonly 和一個 writeable 的結構構成一個 container 的運行目錄,每一個被稱作一個 Layer。如下圖:
得益於 AUFS 的特性,每一個對 readonly 層文件或目錄的修改都只會存在於上層的 writeable 層中。
這樣,由於不存在競爭, 多個 container 可以共享 readonly 的 layer。
所以 docker 將 readonly 的層稱作 image,對於 container 而言整個 rootfs 都是 read-write 的,但事實上所有的修改都寫入最上層的 writeable 層中。
image 不保存用戶狀態,可以用於模板、重建和復制。
某個鏡像:
基於該鏡像創建的容器:
上層的 image 依賴下層的 image,因此 docker 中把下層的 image 稱作父 image,沒有父 image 的 image 稱作 base image。
因此想要從一個 image 啟動一個 container,docker 會先加載其父 image 直到 base image,用戶的進程運行在 writeable 的 layer 中。
所有 parent image 中的數據信息以及 ID、網絡和 lxc 管理的資源限制等具體 container 的配置,構成一個 docker 概念上的 container。如下圖:
Docker image 采用分層結構的好處
共享資源,節省存儲空間:有多個鏡像都從相同的 base 鏡像構建而來,那么宿主機只需在磁盤上保存一份 base 鏡像,同時內存中也只需加載一份 base 鏡像,就可以為所有容器服務了。而且鏡像的每一層都可以被共享。
快速部署:如果要部署多個 container,base image 可以避免多次拷貝。
內存更省:因為多個 container 共享 base image,以及 OS 的 disk 緩存機制,多個 container 中的進程命中緩存內容的幾率大大增加。
升級更方便:相比於 copy-on-write 類型的文件系統,base-image 也是可以掛載為可 writeable 的,可以通過更新 base image 而一次性更新其之上的 container。
允許在不更改 base-image 的同時修改其目錄中的文件,所有寫操作都發生在最上層的 writeable 層中。
四、Docker 鏡像 commit
docker commit 提交容器副本使之成為一個新的鏡像
# docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要創建的目標鏡像名:[標簽名] # 下載鏡像 docker pull tomcat # 啟動鏡像 docker run -d -p 8080:8080 tomcat # 查看容器ID docker ps -a # 進入容器 docker exec -it a41c393cfa45 /bin/bash # 刪除 tomcat rm -rf /usr/local/tomcat/webapps/* # 退出容器 exit # 生成新鏡像 docker commit -m=“沒有webapps的tomcat鏡像” -a=“jhxxb” a41c393cfa45 jhxxb/tomcat-del:1.0 # 查看生成的新鏡像 docker images # 運行新鏡像(需要指定版本,默認為 latest) docker run -d -p 8080:8080 jhxxb/tomcat-del:1.0
可以看到新鏡像的 webapps 目錄下沒有文件
http://tiewei.github.io/cloud/Docker-Getting-Start/
https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay2-driver-works