天天看點

docker存儲-overlayfs.鏡像底層原理/volume原理

1.介紹

聯合檔案系統,overlayFs依賴并建立在其它的檔案系統之上(例如ext4fs和xfs等等),并不直接參與磁盤空間結構的劃分,僅僅将原來底層檔案系統中不同的目錄進行“合并”.

2.指令

mount -t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged
           

1)lowerdir=xxx:指定使用者需要挂載的lower層目錄(支援多lower,最大支援500層);

2)upperdir=xxx:指定使用者需要挂載的upper層目錄;

3)workdir=xxx:指定檔案系統的工作基礎目錄,挂載後内容會被清空,且在使用過程中其内容使用者不可見;

4)  merged:  最後merge到哪個目錄

docker存儲-overlayfs.鏡像底層原理/volume原理
  • 對使用者來說,他隻知道有一個merge目錄,merge下的檔案來自哪個lower,哪個upper,他都不知道.
  • merge規則:如果存在同名檔案,那麼upper>lower[n]>lower[n+1].如果存在同名目錄,那麼取并集.
  • 讀寫規則:
  1. 對merge檔案的操作:如果操作的檔案原屬于upper目錄,那麼會直接造成對源檔案的修改;如果操作的檔案原屬于lower目錄,那麼會複制一份到upper目錄.從此原lower中的檔案與merge目錄沒有任何關系,有關系的是upper下的同名檔案.
  2. 對原檔案的操作:對原檔案的操作,均會影響merged檔案的内容,因為他們本身就是映射的.

3.實際操作:

建立一些目錄以及檔案.

[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   └── l1-2
├── l2
│   ├── l2-1
│   └── l2-2
├── result
├── u
│   └── u1
└── work
           

執行mount操作

[[email protected] testAufs]# mount -t overlay overlay -o lowerdir=l1:l2,upperdir=u,workdir=work result
           

檢視目前結構

[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   └── l1-2
├── l2
│   ├── l2-1
│   └── l2-2
├── result
│   ├── l1-1
│   ├── l1-2
│   ├── l2-1
│   ├── l2-2
│   └── u1
├── u
│   └── u1
└── work
    └── work
           

由此可見: l1,l2,u目錄下的檔案全部merge到了 result目錄.下面做一些測試

3.1.修改原檔案,看是否merge後的檔案也會改.

[[email protected] testOverlay]# echo "old l1">l1/l1-1
[[email protected] testOverlay]# cat l1/l1-1
old l1
[[email protected] testOverlay]# cat result/l1-1
old l1
           

可見,檔案已經改了

3.2.修改result中的檔案.修改原本屬于upper的檔案

[[email protected] testOverlay]# echo "upper txt">result/u1
You have new mail in /var/spool/mail/root
[[email protected] testOverlay]# cat result/u1
upper txt
[[email protected] testOverlay]# cat u/u1
upper txt
[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   └── l1-2
├── l2
│   ├── l2-1
│   └── l2-2
├── result
│   ├── l1-1
│   ├── l1-2
│   ├── l2-1
│   ├── l2-2
│   └── u1
├── u
│   └── u1
└── work
    └── work
           

3.3.修改result下原本屬于lower層的檔案.

[[email protected] testOverlay]# echo "result/lower txt">result/l2-1
[[email protected] testOverlay]# cat result/l2-1
result/lower txt
[[email protected] testOverlay]# cat l2/l2-1
[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   └── l1-2
├── l2
│   ├── l2-1
│   └── l2-2
├── result
│   ├── l1-1
│   ├── l1-2
│   ├── l2-1
│   ├── l2-2
│   └── u1
├── u
│   ├── l2-1
│   └── u1
└── work
    └── work
           

注意這裡:

result/l2-1 内容變了,但是原本目錄下 l2/l2-1沒變,因為是隻讀層, upper層下多了l2-1檔案.此時資料是更改的内容.此時upper下的同名檔案隐藏掉lower下的檔案.你再修改lower下的檔案,result的内容也不會變了.

3.4.動态添加一個檔案

3.4.1 添加到 lower,在upper無同名./添加到upper,lower無同名

[[email protected] l1]# touch l1-add
[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   ├── l1-2
│   └── l1-add
├── l2
│   ├── l2-1
│   └── l2-2
├── result
│   ├── l1-1
│   ├── l1-2
│   ├── l1-add
│   ├── l2-1
│   ├── l2-2
│   └── u1
├── u
│   ├── l2-1
│   └── u1
└── work
    └── work


######添加到upper,lower無同名#########
[[email protected] testOverlay]# tree .
.
├── l1
│   ├── l1-1
│   ├── l1-2
│   └── l1-add
├── l2
│   ├── l2-1
│   └── l2-2
├── result
│   ├── l1-1
│   ├── l1-2
│   ├── l1-add
│   ├── l2-1
│   ├── l2-2
│   └── u4
├── u
│   ├── l1-2
│   ├── l2-1
│   └── u4
└── work
    └── work
           

多會合并的

4.2 添加lower,且upper有同名/ 添加upper,且lower有同名/添加upper,在lower有同名,都不行

###添加lower,在upper有同名####肯定無效
[[email protected] testOverlay]# touch l1/u4
You have new mail in /var/spool/mail/root
[[email protected] testOverlay]# echo "11">l1/u4
[[email protected] testOverlay]# cat result/
l1-1    l1-2    l1-add  l2-1    l2-2    u4
[[email protected] testOverlay]# cat result/u4

###添加lower,在lower有同名####  無效
[[email protected] testOverlay]# echo "l1 add">l1/l2-2
[[email protected] testOverlay]# cat result/l
l1-1    l1-2    l1-add  l2-1    l2-2
[[email protected] testOverlay]# cat result/l
l1-1    l1-2    l1-add  l2-1    l2-2
[[email protected] testOverlay]# cat result/l
l1-1    l1-2    l1-add  l2-1    l2-2
[[email protected] testOverlay]# cat result/l2-2


###添加upper,在lower有同名####  無效
           

3.5.删除呢??

删除需要考慮到幾種場景.

a删除的檔案是upper層,且lower層沒有同名檔案,很好辦.直接删除就行了

b删除lower檔案,并且upper沒有同名檔案名.

有點難搞,要保證lower原檔案不能删除,又要保證使用者見不到該檔案. overlayFs使用了障眼法.Whiteout檔案.Whiteout檔案在使用者删除檔案時建立,用于屏蔽底層的同名檔案,同時該檔案在merge層是不可見的

類似一個黑名單

當使用者在merge層通過ls指令(将通過readddir系統調用)檢查父目錄的目錄項時,overlayfs會自動過過濾掉和whiteout檔案自身以及和它同名的lower層檔案和目錄,達到了隐藏檔案的目的,讓使用者以為檔案已經被删除了

c要删除的檔案是upper層覆寫lower層的檔案,要删除的目錄是上下層合并的目錄

要把upper層的删除,并且屏蔽掉lower層檔案

3.6.建立一個檔案或目錄

3.7.rename檔案/目錄

4.docker怎麼使用的

[[email protected] data]# mount|grep overlay
overlay on /var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/AYCIYBZZOU2SBB7HAWWC53G5MV:/var/lib/docker/overlay2/l/7AC2GBWZ3VYQGR2IW6FVGTJELH,upperdir=/var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/diff,workdir=/var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/work)
overlay on /data/dockerTest/testAufs/merged type overlay (rw,relatime,lowerdir=a:b,upperdir=c,workdir=result)
overlay on /data/dockerTest/testOverlay/result type overlay (rw,relatime,lowerdir=l1:l2,upperdir=u,workdir=work)
overlay on /data/dockerTest/testOverlay/m type overlay (rw,relatime,lowerdir=a:b,upperdir=c,workdir=work)


後面三個是我們測試時用的

第一個是目前docker啟動的容器用的
           

可以看到:

1.lower是/var/lib/docker/overlay2/l/  檔案夾下的某幾個檔案

隻讀層,這些檔案一起構成了某個鏡像.例如 Ubuntu+java+tomcat+nginx+webApp構成了整個應用的鏡像

Dockerfile 中的每個原語執行後,都會生成一個對應的鏡像層.即使原語本身并沒有明顯地修改檔案的操作(比如,ENV 原語),它對應的層也會存在。隻不過在外界看來,這個層是空的

2.upper是upperdir=/var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/diff 檔案

這個是讀寫層.容器就是一個讀寫層,我們在容器裡增删改操作會都是寫在這裡.

一旦我們容器運作時,送出成為一個鏡像.那麼  會把該讀寫層,變為隻讀層!!主要:容器是可寫,鏡像是隻讀!

3.merge檔案是/var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/merged  這不就是作業系統嗎??

[[email protected]llchain-tool-02 merged]# ll /var/lib/docker/overlay2/44f8d7c28f545bd10acaea67d7138774445389171a66b418dae0d83469c8e29b/merged
total 48
drwxr-xr-x 2 root      root      12288 Oct 13 07:47 bin
drwxr-xr-x 1 root      root       4096 Nov 25 12:49 dev
drwxr-xr-x 1 root      root       4096 Nov 25 12:49 etc
drwxr-xr-x 2 nfsnobody nfsnobody  4096 Oct 13 07:47 home
drwxr-xr-x 2 root      root       4096 Nov 25 12:49 proc
drwx------ 2 root      root       4096 Oct 13 07:47 root
drwxr-xr-x 2 root      root       4096 Nov 25 12:49 sys
drwxrwxrwt 2 root      root       4096 Oct 13 07:47 tmp
drwxr-xr-x 3 root      root       4096 Oct 13 07:47 usr
drwxr-xr-x 4 root      root       4096 Oct 13 07:47 var
           
docker存儲-overlayfs.鏡像底層原理/volume原理

容器建立成功後,會添加一個upper層,運作時的修改都是在針對 upper層操作.如果要修改lower層呢??那麼需要寫時複制了,就是把lower層複制到upper層,然後你就可以修改了.

如果容器退出,那麼upper層會删除掉,之前的lower層不會變,你再用同樣的鏡像去生成一個容器,還是使用同樣的lower層.

5.volume原理

剛剛我們分析了docker的存儲層的原理.在此總結下:docker的鏡像是又多個隻讀層疊加的.容器是這些隻讀層+讀寫層.如果運作的時候,對檔案作出了修改,那麼會使用cow機制,将lower層資料拷貝到upper層.當删除容器後,讀寫層也會删除.

1.啟動一個容器,使用volume  

docker run -it --name volume-test -h CONTAINER -v /data/testvolume busybox /bin/sh
           

2.檢視容器中的資料.啥都沒有

/data/testvolume # ls /data/testvolume/
/data/testvolume #
           

3.檢視

[[email protected] data]# docker inspect volume-test|grep volume
        "Name": "/volume-test",
                "Type": "volume",
                "Source": "/var/lib/docker/volumes/c40fae3cefad3ffb1eac6fa584a131551ff7c3e5723b15a153a9ca9332316af3/_data",
                "Destination": "/data/testvolume",
                "/data/testvolume": {}
           

說明/data/testvolume 映射在了/var/lib/docker/volumes/c40fae3cefad3ffb1eac6fa584a131551ff7c3e5723b15a153a9ca9332316af3/_data

注意,這裡是docker volumes目錄,說明volume已經繞過了overlayfs.我們在_data下新增一個檔案

[[email protected] ~]# cd /var/lib/docker/volumes/e124d9f2cf43d41f6c2882bac080db974636c6cbbcd01f28aaf3ffe553b4514b/_data
[[email protected] _data]# touch testhh
           

檢視容器

/data/testvolume # ls /data/testvolume/
testhh
           

沒有問題

我們在容器裡建立

/data/testvolume # touch /data/testvolume/testhh2

在主控端的目錄上
[[email protected] _data]# ls /var/lib/docker/volumes/e124d9f2cf43d41f6c2882bac080db974636c6cbbcd01f28aaf3ffe553b4514b/_data
testhh  testhh2
           

我們再看下mount

[[email protected] data]# mount|grep overlay
overlay on /data/dockerTest/testAufs/merged type overlay (rw,relatime,lowerdir=a:b,upperdir=c,workdir=result)
overlay on /data/dockerTest/testOverlay/result type overlay (rw,relatime,lowerdir=l1:l2,upperdir=u,workdir=work)
overlay on /data/dockerTest/testOverlay/m type overlay (rw,relatime,lowerdir=a:b,upperdir=c,workdir=work)
overlay on /var/lib/docker/overlay2/d95533f356ba958c012a197d35cc8fa8e36c56d1d852ce731b2f5c847b65136a/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/ZOOVPE6ITB5JBEWQW3AIQBLXTE:/var/lib/docker/overlay2/l/7AC2GBWZ3VYQGR2IW6FVGTJELH,upperdir=/var/lib/docker/overlay2/d95533f356ba958c012a197d35cc8fa8e36c56d1d852ce731b2f5c847b65136a/diff,workdir=/var/lib/docker/overlay2/d95533f356ba958c012a197d35cc8fa8e36c56d1d852ce731b2f5c847b65136a/work)
           

确實沒有使用overlayfs

參考:https://blog.csdn.net/luckyapple1028/article/details/78075358 這個文章寫得很好

https://zhuanlan.zhihu.com/p/41958018