原文連接:https://arkingc.github.io/2017/05/05/2017-05-05-docker-filesystem-overlay/
docker原文:https://docs.docker.com/storage/storagedriver/overlayfs-driver/
OverlayFS是和AUFS相似的聯合文件系統(union filesystem),它有如下特點:
- 設計簡潔;
- 內核3.18開始已經併入內核主線
- 可能更快
因此,它在社區迅速獲得廣泛關注並被很多人認爲是AUFS的繼承。但是它任然很年輕,
因此在生產環境中使用時要謹慎
docker的overlay存儲驅動利OverlayFS的一些特徵來構建以及管理鏡像和容器的磁盤結構
docker1.12後推出的overlay2在inode的利用方面比ovelay更有效overlay2要求內核版本大於等於4.0
overlay
如下圖所示,Overlay在主機上用到2個目錄,這2個目錄被看成是overlay的層。
upperdir爲容器層、lowerdir爲鏡像層使用聯合掛載技術將它們掛載在同一目錄(merged)下,提供統一視圖
圖片來源: Docker文檔
當容器層和鏡像層擁有相同的文件時,容器層的文件可見,隱藏了鏡像層相同的文件。
容器掛載目錄(merged)提供了統一視圖
overlay只使用2層,意味着多層鏡像不會被實現爲多個OverlayFS層。每個鏡像被實現爲自己的目錄,
這個目錄在路徑/var/lib/docker/overlay下。硬鏈接被用來索引和低層共享的數據,節省了空間
當創建一個容器時,overlay驅動連接代表鏡像層頂層的目錄(只讀)和一個代表容器層的新目錄(讀寫)
例子:鏡像和容器的磁盤結構[overlay]
|
root@chenximing-MS-7823:/home/chenximing# tree /var/lib/docker/overlay/
/var/lib/docker/overlay/
|
一開始overlay路徑下爲空,用docker pull命令下載一個由5層鏡像層組成的docker鏡像:
|
chenximing@chenximing-MS-7823:~$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
c62795f78da9: Pull complete
d4fceeeb758e: Pull complete
5c9125a401ae: Pull complete
0062f774e994: Pull complete
6b33fd031fac: Pull complete
Digest: sha256:c2bbf50d276508d73dd865cda7b4ee9b5243f2648647d21e3a471dd3cc4209a0
Status: Downloaded newer image for ubuntu:latests
|
此時,在路徑/var/lib/docker/overlay/下,每個鏡像層都有一個對應的目錄,包含了該層鏡像的內容,通過tree命令發現,每個鏡像層下只包含一個root目錄 (因爲docker1.10開始,使用基於內容的尋址,因此目錄名和鏡像層的id不一致)
|
root@chenximing-MS-7823:/home/chenximing# tree -L 2 /var/lib/docker/overlay/
/var/lib/docker/overlay/
├── 3279a41fd358cdda798d99cc2da0425b4836a489083ae9db4aedc834f426915a
│ └── root
├── 33629fe3999e692ecbeb340f855a2d05ddf4e173ea915041be217e1c9cc8a48f
│ └── root
├── 6ab876fcc7ad584dd1eebae0d9304abb22561012f6adb87828f57906d799c33b
│ └── root
├── 77806a4b8257cd5508a1131d4d47c2d4b4d51703a1cc0dd8daddf0e86a68d492
│ └── root
└── ed271f2159e3c9de18ede980e4e2ecb0ef39b96927d446ba93deab0b6ff1a8e3
└── root
|
每一層都包含了”該層獨有的文件”以及”和其低層共享的數據的硬連接”。如ls命令,每一層都使用一個硬鏈接來指向實際ls命令的inode號(405241):
|
root@chenximing-MS-7823:/home/chenximing# ls -i /var/lib/docker/overlay/3279a41fd358cdda798d99cc2da0425b4836a489083ae9db4aedc834f426915a/root/bin/ls
405241 /var/lib/docker/overlay/3279a41fd358cdda798d99cc2da0425b4836a489083ae9db4aedc834f426915a/root/bin/ls
root@chenximing-MS-7823:/home/chenximing# ls -i /var/lib/docker/overlay/33629fe3999e692ecbeb340f855a2d05ddf4e173ea915041be217e1c9cc8a48f/root/bin/ls
405241 /var/lib/docker/overlay/33629fe3999e692ecbeb340f855a2d05ddf4e173ea915041be217e1c9cc8a48f/root/bin/ls
|
使用剛剛拉取的ubuntu鏡像創建一個容器,用docker ps命令查看:
|
root@chenximing-MS-7823:/home/chenximing# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8963ffb422fa ubuntu "/bin/bash" 32 minutes ago Up 52 seconds container_1
|
創建容器時,實際上是在已有的鏡像層上創建了一層容器層,容器層在路徑/var/lib/docker/overlay下也存在對應的目錄:
|
root@chenximing-MS-7823:/home/chenximing# ls /var/lib/docker/overlay/
3279a41fd358cdda798d99cc2da0425b4836a489083ae9db4aedc834f426915a
33629fe3999e692ecbeb340f855a2d05ddf4e173ea915041be217e1c9cc8a48f
6ab876fcc7ad584dd1eebae0d9304abb22561012f6adb87828f57906d799c33b
6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d //創建容器後新增的目錄
6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d-init //創建容器後新增的目錄
77806a4b8257cd5508a1131d4d47c2d4b4d51703a1cc0dd8daddf0e86a68d492
ed271f2159e3c9de18ede980e4e2ecb0ef39b96927d446ba93deab0b6ff1a8e3
|
“6abc47……”和“6abc47…..-init”爲創建容器後新增的目錄。查看這兩個目錄的內容:
|
root@chenximing-MS-7823:/home/chenximing# tree -L 3 /var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d*/
/var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d/
├── lower-id
├── merged
├── upper
│ ├── dev
│ │ └── console
│ ├── etc
│ │ ├── hostname
│ │ ├── hosts
│ │ ├── mtab -> /proc/mounts
│ │ └── resolv.conf
│ └── root
└── work
└── work
/var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d-init/
├── lower-id
├── merged
├── upper
│ ├── dev
│ │ └── console
│ └── etc
│ ├── hostname
│ ├── hosts
│ ├── mtab -> /proc/mounts
│ └── resolv.conf
└── work
└── work
|
“6abc47……”爲讀寫層,“6abc47…..-init”爲初始層。初始層中大多是初始化容器環境時,與容器相關的環境信息,如容器主機名,主機host信息以及域名服務文件等。所有對容器做出的改變都記錄在讀寫層
文件lower-id用來索引該容器使用的鏡像層,upper目錄包含了容器層的內容,每當啓動一個容器時,會將lower-id指向的鏡像層目錄以及upper目錄聯合掛載到merged目錄,因此,容器內的視角就是merged目錄下的內容。而work目錄則是用來完成如copy-on_write的操作
看看容器使用到了哪一層鏡像層:
|
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d/lower-id
ed271f2159e3c9de18ede980e4e2ecb0ef39b96927d446ba93deab0b6ff1a8e3
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d-init/lower-id
ed271f2159e3c9de18ede980e4e2ecb0ef39b96927d446ba93deab0b6ff1a8e3
|
在剛纔創建的容器中創建一個文件:
|
root@8963ffb422fa:/# touch file
root@8963ffb422fa:/# echo "hello world" > file
root@8963ffb422fa:/# ls
bin dev file lib media opt root sbin sys usr
boot etc home lib64 mnt proc run srv tmp var
|
此時再觀察“6abc47……”目錄(讀寫層):
|
root@chenximing-MS-7823:/home/chenximing# tree -L 3 /var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d/
/var/lib/docker/overlay/6abc47fcf668b6820a2a9a8b0d0c6150f9df61ab5a323783630fac3fd282144d/
├── lower-id
├── merged
├── upper
│ ├── dev
│ │ └── console
│ ├── etc
│ │ ├── hostname
│ │ ├── hosts
│ │ ├── mtab -> /proc/mounts
│ │ └── resolv.conf
│ ├── file
│ └── root
└── work
└── work
|
發現upper目錄下多出了一個file文件,就是剛纔在容器中創建的文件
overlay2
和overlay爲了實現“兩個目錄反映多層鏡像“而使用硬鏈接不同,overlay2驅動天生支持多層。(最多128)
因此,overlay2在使用docker層相關的命令時,能提供更好的性能(如:docker build、docker commit)。而且overlay2消耗的inode節點更少
例子:鏡像和容器的基於磁盤的結構[overlay2]
docker pull ubuntu拉取完一個5層的Ubuntu鏡像後,/var/lib/docker/overlay2下可以看到6個目錄:
|
root@chenximing-MS-7823:/home/chenximing# tree -L 2 /var/lib/docker/overlay2
/var/lib/docker/overlay2
├── 1d18eac18e483e5af46d52673e254cb89996041d91356c6dd1f0ac1518ba130a
│ ├── diff
│ └── link //文件
├── 28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6
│ ├── diff
│ ├── link //文件
│ ├── lower //文件
│ ├── merged
│ └── work
├── 299397034eb96f22d544bf544c9ef993fa32571f466bd8a881aec0fc5a94a8df
│ ├── diff
│ ├── link //文件
│ ├── lower //文件
│ ├── merged
│ └── work
├── 8c0de7df4581df4787b08a28356cc8d7ba7b420c70dc36cc0615afdafb6ee15a
│ ├── diff
│ ├── link //文件
│ ├── lower //文件
│ ├── merged
│ └── work
├── f21a47541026214e519fccdf8b838ac2c4e11a1a2dd6a5febc061381a1972ad7
│ ├── diff
│ ├── link //文件
│ ├── lower //文件
│ ├── merged
│ └── work
└── l
├── 5DJFQNGXSA5CVOC6NA6HPUCXXB -> ../299397034eb96f22d544bf544c9ef993fa32571f466bd8a881aec0fc5a94a8df/diff
├── EGQNS3O24ONBL5BJSGNTX4NP6E -> ../1d18eac18e483e5af46d52673e254cb89996041d91356c6dd1f0ac1518ba130a/diff
├── JWB63ZJDZOTK5N22OMR5BKUVMG -> ../8c0de7df4581df4787b08a28356cc8d7ba7b420c70dc36cc0615afdafb6ee15a/diff
├── UZHRLLTPQMODQQYBLN6NOT6N2K -> ../28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6/diff
└── X76VPZDDKIW3GLWBFUHKDFBEPE -> ../f21a47541026214e519fccdf8b838ac2c4e11a1a2dd6a5febc061381a1972ad7/diff
24 directories, 9 files
|
”l“目錄包含一些符號鏈接作爲縮短的層標識符. 這些縮短的標識符用來避免掛載時超出頁面大小的限制
|
root@chenximing-MS-7823:/home/chenximing# ls -l /var/lib/docker/overlay2/l/
總用量 20
lrwxrwxrwx 1 root root 72 4月 20 17:31 5DJFQNGXSA5CVOC6NA6HPUCXXB -> ../299397034eb96f22d544bf544c9ef993fa32571f466bd8a881aec0fc5a94a8df/diff
lrwxrwxrwx 1 root root 72 4月 20 17:31 EGQNS3O24ONBL5BJSGNTX4NP6E -> ../1d18eac18e483e5af46d52673e254cb89996041d91356c6dd1f0ac1518ba130a/diff
lrwxrwxrwx 1 root root 72 4月 20 17:31 JWB63ZJDZOTK5N22OMR5BKUVMG -> ../8c0de7df4581df4787b08a28356cc8d7ba7b420c70dc36cc0615afdafb6ee15a/diff
lrwxrwxrwx 1 root root 72 4月 20 17:31 UZHRLLTPQMODQQYBLN6NOT6N2K -> ../28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6/diff
lrwxrwxrwx 1 root root 72 4月 20 17:31 X76VPZDDKIW3GLWBFUHKDFBEPE -> ../f21a47541026214e519fccdf8b838ac2c4e11a1a2dd6a5febc061381a1972ad7/diff
|
最底層包含”link”文件(不包含lower文件,因爲是最底層),在上面的結果中“1d8e….”爲最底層。這個文件記錄着作爲標識符的更短的符號鏈接的名字、最底層還有一個”diff”目錄(包含實際內容)
|
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay2/1d18eac18e483e5af46d52673e254cb89996041d91356c6dd1f0ac1518ba130a/link
EGQNS3O24ONBL5BJSGNTX4NP6E
root@chenximing-MS-7823:/home/chenximing# ls /var/lib/docker/overlay2/1d18eac18e483e5af46d52673e254cb89996041d91356c6dd1f0ac1518ba130a/diff/
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
|
從第二層開始,每層鏡像層包含”lower“文件,根據這個文件可以索引構建出整個鏡像的層次結構。”diff“文件(層的內容)。還包含”merged“和”work”目錄,用途和overlay一樣
|
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay2/28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6/link
UZHRLLTPQMODQQYBLN6NOT6N2K
root@chenximing-MS-7823:/home/chenximing# ls /var/lib/docker/overlay2/28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6/diff/
etc sbin usr var
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay2/28702e0cca9ff9a3245ce7e61326d098788e855ea599bf160465f537756a56a6/lower
l/EGQNS3O24ONBL5BJSGNTX4NP6E
|
再來看看容器層,容器層的文件構成和鏡像層類似(這點和overlay不同),使用剛剛拉取的ubuntu鏡像創建一個容器,/var/lib/docker/overlay2目錄下新增2個目錄:
|
├── 2558ed8dd7051c1e78ea980590a228100ec3d299c01b35e9b7fa503723593d19
│ ├── diff
│ ├── link
│ ├── lower
│ ├── merged
│ └── work
├── 2558ed8dd7051c1e78ea980590a228100ec3d299c01b35e9b7fa503723593d19-init
│ ├── diff
│ ├── link
│ ├── lower
│ ├── merged
│ └── work
└── l
├── 7H7MUMX4IOAVLIJ2YPLR5MZOO5 -> ../2558ed8dd7051c1e78ea980590a228100ec3d299c01b35e9b7fa503723593d19-init/diff
├── EBSBKJBLA2WYBHTMHKSMCEEWNP -> ../2558ed8dd7051c1e78ea980590a228100ec3d299c01b35e9b7fa503723593d19/diff
root@chenximing-MS-7823:/home/chenximing# cat /var/lib/docker/overlay2/2558ed8dd7051c1e78ea980590a228100ec3d299c01b35e9b7fa503723593d19/lower
l/7H7MUMX4IOAVLIJ2YPLR5MZOO5:l/5DJFQNGXSA5CVOC6NA6HPUCXXB:l/JWB63ZJDZOTK5N22OMR5BKUVMG:l/X76VPZDDKIW3GLWBFUHKDFBEPE:l/UZHRLLTPQMODQQYBLN6NOT6N2K:l/EGQNS3O24ONBL5BJSGNTX4NP6E
|
容器的讀寫
對於讀,考慮下列3種場景:
- 讀的文件不在容器層:如果讀的文件不在容器層,則從鏡像層進行讀
- 讀的文件只存在在容器層:直接從容器層讀
- 讀的文件在容器層和鏡像層:讀容器層中的文件,因爲容器層隱藏了鏡像層同名的文件
對於寫,考慮下列場景:
- 寫的文件不在容器層,在鏡像層:由於文件不在容器層,因此overlay/overlay2存儲驅動使用copy_up操作從鏡像層拷貝文件到容器層,然後將寫入的內容寫入到文件新的拷貝中
- 刪除文件和目錄:刪除鏡像層的文件,會在容器層創建一個whiteout文件來隱藏它;刪除鏡像層的目錄,會創建opaque目錄,它和whiteout文件有相同的效果
- 重命名目錄:對一個目錄調用rename(2)僅僅在資源和目的地路徑都在頂層時才被允許,否則返回EXDEV
配置Docker使用overlay/overlay2存儲驅動
- 配置overlay要求內核版本大於等於3.18,且加載了overlay內核模塊;
- 配置overlay2要求內核版本大於等於4.0;
- docker daemon處於stopped狀態;
OverlayFS能在大多數Linux文件系統上運行,但是ext4是目前在生產環境中被推薦的
1) stop Docker daemon
|
$ sudo service docker stop
|
2) 確認內核版本以及overlay內核模塊已經加載
|
#查看內核版本
$ uname -r
#查看內核是否已加載overlay模塊
$ lsmod | grep overlay
overlay
|
如果未加載overlay模塊,假設你的內核已經編譯了overlay模塊,則可以通過下列命令進行加載,或者在啓動docker服務時,會自動加載overlay模塊:
3) 啓動docker daemon(使用overlay/overlay2存儲驅動)
方法一(推薦):
在/etc/docker/路徑下創建daemon.json文件,並添加下列內容:
|
{
"storage-driver": "overlay2"
}
|
然後啓動docker服務:
|
$ sudo service docker start
|
方法二:
|
$ dockerd --storage-driver=overlay &
[1] 29403
root@ip-10-0-0-174:/home/ubuntu# INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
INFO[0000] Option DefaultDriver: bridge
INFO[0000] Option DefaultNetwork: bridge
|
4) 覈實daemon已經在使用overlay/overlay2
|
$ docker info
Containers: 0
Images: 0
Storage Driver: overlay
Backing Filesystem: extfs
...
|
OverlayFS and Docker 性能
一般來說,overlay/overlay2很快,幾乎肯定比aufs和devicemapper快。在某些特定場景下,還可能比btrfs快。
此外,還有幾點overlay/overlay2驅動性能相關的注意事項:
- 頁緩存:OverlayFS支持頁緩存共享,意味着多個容器訪問相同的文件能夠共享一個單一的page cache entry
使得overlay/overlay2驅動能高效使用內存,是PaaS以及其它高密度場景一個好的選擇
- copy_up:對鏡像層大文件進行寫操作時,copy-on-write會給寫操作帶來大量延遲
- inode 限制:使用overlay會引起過度的inode消耗,消耗會隨着主機上的鏡像和容器的增加而增加。擁有大量鏡像的主機在大量容器啓動和停止時可能會耗盡inodes。不幸的是你只能在文件系統創建時指定inode數,因此你可能需要考慮將/var/lib/docker放在另一個獨立的設備上,或者在創建文件系統時手動修改inode值。而overlay2則沒有這樣的問題
- RPM和Yum:OverlayFS僅實現了POSIX標準的一部分,某些操作還會違反POSIX標準,copy_up操作就是其中一個
下面是提升OverlayFS驅動性能的最佳實踐:
- SSD:爲了獲得最佳性能,一個通常的想法是使用諸如SSD這類更快的存儲設備
- 使用數據卷: 數據卷提供了最好的以及最可預見的性能。因爲繞過了存儲驅動,因此不會存在瘦供給和copy-on-write帶來的潛在性能開銷。因此,寫操作較頻繁的數據應該放在數據捲上