Docker技術基礎:Union File System

Github-blog
CSDN

Docker images and layers

在介紹Docker存儲驅動之前,我們先介紹一下Docker是如何建立image,又如何在image的基礎上創建容器的。
Docker的image是由一組layers組合起來得到的,每一層layer對應的是Dockerfile中的一條指令。這些layers中,一層layer爲R/W layer,即 container layer,其他layers均爲read-only layer(分析見Union File System)。
PS: Dockerfile中只允許最後一個CMD或ENTRYPOINT生效,也與之對應,Dockerfile中其他命令生成的layer爲Read-only的,CMD或ENTRYPOINT生成的layer是R/W的。

以ubuntu:15.04的image爲例,其image結構示意圖如下(截自docker docs):

image結構示意圖

當創建多臺容器的時候,我們所有的寫操作都是發生在R/W層,其FS結構示意圖如下:
多容器FS結構示意圖

Union File System

Docker的存儲驅動的實現是基於Union File System,簡稱UnionFS,他是一種爲Linux 、FreeBSD 和NetBSD 操作系統設計的,把其他文件系統聯合到一個聯合掛載點的文件系統服務。它用到了一個重要的資源管理技術,叫寫時複製。寫時複製(copy-on-write),也叫隱式共享,是一種對可修改資源實現高效複製的資源管理技術。對於一個重複資源,若不修改,則無需立刻創建一個新的資源,該資源可以被共享使用。當發生修改的時候,纔會創建新資源。這會大大減少對於未修改資源複製的消耗。Docker正式基於此去創建images和containers。關於Docker中Union file system的應用官方文檔介紹如下:

## Union file system
Union file systems implement a [union
mount](https://en.wikipedia.org/wiki/Union_mount) and operate by creating
layers. Docker uses union file systems in conjunction with
[copy-on-write](#copy-on-write 劃重點) techniques to provide the building blocks for
containers, making them very lightweight and fast.

For more on Docker and union file systems, see [Docker and AUFS in
practice](https://docs.docker.com/engine/userguide/storagedriver/aufs-driver/),
[Docker and Btrfs in
practice](https://docs.docker.com/engine/userguide/storagedriver/btrfs-driver/),
and [Docker and OverlayFS in
practice](https://docs.docker.com/engine/userguide/storagedriver/overlayfs-driver/)

Example implementations of union file systems are
[UnionFS](https://en.wikipedia.org/wiki/UnionFS),
[AUFS](https://en.wikipedia.org/wiki/Aufs), and
[Btrfs](https://btrfs.wiki.kernel.org/index.php/Main_Page).

AUFS

AUFS,全稱Advanced Multi-Layered Unification Filesystem。AUFS重寫了早期的UnionFS 1.x,提升了其可靠性和性能,是早期Docker版本的默認的存儲驅動。(Docker-CE目前默認使用OverlayFS)。

AUFS結構示意圖

Ubuntu/Debian(Stretch之前的版本)上的Docker-CE可以通過配置DOCKER_OPTS="-s=aufs"進行修改,同時內核中需要加載AUFS module,image的增刪變動都會發生在/var/lib/docker/aufs目錄下。

AUFS下文件讀操作

1、文件存在於container-layer:直接從container-layer進行讀取;
2、文件不存在於container-layer:自container-layer下一層開始,逐層向下搜索,找到該文件,並從找到文件的那一層layer中讀取文件;
3、當文件同時存在於container-layer和image-layer,讀取container-layer中的文件。
簡而言之,從container-layer開始,逐層向下搜索,找到該文件即讀取,停止搜索。

AUFS下修改文件或目錄

寫操作
1、對container-layer中已存在的文件進行寫操作:直接在該文件中進行操作(新文件直接在container-layer創建&修改);
2、對image-layers中已存在的文件進行寫操作:將該文件完整複製到container-layer,然後在container-layer對這份copy進行寫操作;
刪除
1、刪除container-layer中的文件/目錄:直接刪除;
2、刪除image-layers中的文件:在container-layer中創建whiteoutfile,image-layer中的文件不會被刪除,但是會因爲whiteout而變得對container而言不可見;
3、刪除image-layers中的目錄:在container-layer中創建opaquefile,作用同whiteout
重命名
1、container-layer文件/目錄重命名:直接操作;
2、image-layer文件重命名:
3、image-layer目錄重命名:在docker的AUFS中沒有支持,會觸發EXDEV

AUFS優點

1、可以在多個運行的container中高效的共享image,可以實現容器的快速啓動,並減少磁盤佔用量;
2、共享image-layers的方式,可以高效的是使用page cache

AUFS缺點

1、性能上不如overlay2;
2、當文件進行寫操作的時候,如果文件過大,或者文件位於底層的image中,則可能會引入高延遲。

OverlayFS

OverlayFS也是採用UFS模式,但相對於AUFS,其性能更高。在Docker中主要有overlay和overlay2兩種實現。Docker-CE默認採用overlay2。

root@xftony:/var/lib/docker# docker info
    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 18.03.0-ce
    Storage Driver: overlay2
    ......

OverlayFS中使用了兩個目錄,把一個目錄置放於另一個之上,並且對外提供單個統一的視角。下層的目錄叫做lowerdir,上層的叫做upperdir。對外展示的統一視圖稱作merged。創建一個容器,overlay驅動聯合鏡像層和一個新目錄給容器。鏡像頂層是overlay中的只讀 lowerdir,容器的新目錄是 可讀寫 的upperdir。它們默認存儲於/var/lib/docker/overlay2/目錄下。如下所示,是剛下載好一個image後,該目錄下的文件結構:

root@xftony:/var/lib/docker/overlay2# tree -L 2
.
├── 82f20fe6e3d9c9a33560b18bd0dcab53afeadca03bb7daea174e736d3ac4ee2d
│   ├── diff
│   ├── link
│   ├── lower
│   └── work
├── 8fa01a5986e8a08c5c6af11c88015013841b89496a8d6cb65d6186dad03a12e6
│   ├── diff
│   └── link
├── a6219957a4e46e40b78cf5d20624e0b42f51a12f83dd2b4c683e33a5932d634b
│   ├── diff
│   ├── link
│   ├── lower
│   └── work
├── bce6bd75c4c2900eb51d3b103073a158ea17be3708461714f19eddb9e2bc9713
│   ├── diff
│   ├── link
│   ├── lower
│   └── work
├── dbafc7976ac255df27aea16935b901745c1cf66487f142ec01b047998f139122
│   ├── diff
│   ├── link
│   ├── lower
│   └── work
└── l
    ├── CMR5LVSFJRXC7QA2ZF5MWLQB5Z -> ../82f20fe6e3d9c9a33560b18bd0dcab53afeadca03bb7daea174e736d3ac4ee2d/diff
    ├── ENKIS3HQUBTP5TXRBSEBREVFSB -> ../a6219957a4e46e40b78cf5d20624e0b42f51a12f83dd2b4c683e33a5932d634b/diff
    ├── EOAX5LBZ75SSQHO6VOVXVMEP6E -> ../dbafc7976ac255df27aea16935b901745c1cf66487f142ec01b047998f139122/diff
    ├── OAFOUB3QEZRY42E4ERJHP6NVJG -> ../8fa01a5986e8a08c5c6af11c88015013841b89496a8d6cb65d6186dad03a12e6/diff
    └── XR6454BGFPITLDXL4D7MPQEUHZ -> ../bce6bd75c4c2900eb51d3b103073a158ea17be3708461714f19eddb9e2bc9713/diff  

其中

l:目錄下存儲了多個軟鏈接,使用短名指向其他各層;
其他一級目錄:例如8fa01a5986e8a08c5等目錄,爲lowerdir,是一層層的鏡像;
diff:包含該層鏡像的具體內容,即upperdirlowerdir,此處都爲lowerdir
link:記錄該目錄對應的短名;
lower:記錄該目錄的所有lowerdir,每一級間使用: 分隔;
work:該目錄是OverlayFS功能需要的,會被如copy_up之類的操作使用;

現在,我們使用該鏡像創建一個container。創建成功後,會發overlay2目錄下多了兩個目錄,l目錄下也多了兩個連接(我已經手動去掉了原有的目錄結構):

root@xftony:/var/lib/docker/overlay2# tree -L 2
.
├── 671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688
│   ├── diff
│   ├── link
│   ├── lower
│   ├── merged
│   └── work
├── 671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688-init
│   ├── diff
│   ├── link
│   ├── lower
│   └── work
├── ...
└── l
    ├── 43XFRTJKKACM22VJ5VHRS4RJE4 -> ../671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688/diff
    ├── CAAAXEW6Q6BCCOG5XVXVVJN2PY -> ../671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688-init/diff
    ├── 
    ...

其中

XXX-init:這是頂層的lowerdir的父目錄,因此也是隻讀的,它的目的是爲了初始化container配置信息,譬如hostname等信息,XXX對應的是upperdir的父目錄名;
XXX:這是upperdir的父目錄,可讀寫,container的寫操作都會發生在該層;
merged:該目錄就是container的mount point,這就是暴露的lowerdirupperdir的統一視圖。任何對容器的改變也影響這個目錄。

此時可以通過mount查看overlay統一試圖中的mount狀態:

root@xftony:/var/lib/docker/overlay2# mount |grep overlay
overlay on /var/lib/docker/overlay2/671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688/merged type overlay (rw,relatime,
lowerdir=/var/lib/docker/overlay2/l/CAAAXEW6Q6BCCOG5XVXVVJN2PY:
/var/lib/docker/overlay2/l/CMR5LVSFJRXC7QA2ZF5MWLQB5Z:
/var/lib/docker/overlay2/l/ENKIS3HQUBTP5TXRBSEBREVFSB:
/var/lib/docker/overlay2/l/XR6454BGFPITLDXL4D7MPQEUHZ:
/var/lib/docker/overlay2/l/EOAX5LBZ75SSQHO6VOVXVMEP6E:
/var/lib/docker/overlay2/l/OAFOUB3QEZRY42E4ERJHP6NVJG,
upperdir=/var/lib/docker/overlay2/671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688/diff,
workdir=/var/lib/docker/overlay2/671ffb27cc5e04f7f7a6c2e61b82c74514df0ff57a2fb47fd45bb1902aa86688/work)
OverlayFS下讀寫操作:

目前感覺基本與AUFS一致,等後續理解深一點在補。
官方介紹在此docker.docs

OverlayFS優點

1、可以在多個運行的container中高效的共享image,可以實現容器的快速啓動,並減少磁盤佔用量;
2、支持頁緩存共享,可以高效的是使用page cache;
3、相較於AUFS等,性能更好。

OverlayFS缺點

1、只支持POSIX標準的一個子集,與其他文件系統的存在不兼容性,如對open和rename操作的支持;

BtrFS, DeviceMapper,ZFS,VFS

待補。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章