docker修改镜像的存储位置_Docker存储原理
背景
正在看一篇論文,名為《Efficient Service Handoff Across Edge Servers via Docker Container Migration》,里面介紹了如何利用docker快速遷移應(yīng)用,對(duì)于一些低延遲的場景比較有用,里面有關(guān)于docker存儲(chǔ)的方面,所以就有了本篇文章
一.Docker的老存儲(chǔ)引擎AUFS
1.1 什么是AUFS
AUFS是一種 Union File System,全稱是Advanced Union File System,主要是把不同物理位置的目錄合并mount到同一個(gè)目錄下
1.2 AUFS的讀寫操作
將多個(gè)目錄mount成一個(gè)后,讀寫操作如下:
- 默認(rèn)情況下,最上層的目錄是讀寫層,下面可以有一個(gè)或者多個(gè)只讀層
- 讀文件時(shí),打開文檔使用O_RDONLY選項(xiàng),從最上面一個(gè)文件開始逐層往下找,打開第一個(gè)找到的文件,并讀取其中的內(nèi)容
- 寫文件時(shí),打開文件使用O_WRONLY和O_RDWR選項(xiàng)
- 如果在最上層找到文件,直接打開文件
- 如果是在只讀層中找到,則將該文件復(fù)制到最上層,然后在最上層打開這個(gè)copy的文件(如果讀寫的文件比較大,這個(gè)過程耗費(fèi)的時(shí)間就會(huì)比較久)
- 刪除文件,在最上層創(chuàng)建一個(gè)whiteout文件,就是在原來文件名字前面加上.wh
二、Docker使用的存儲(chǔ)引擎
2.1 Docker 默認(rèn)的存儲(chǔ)引擎
AUFS是及更早版本的首選存儲(chǔ)驅(qū)動(dòng)程序,之后的docker版本默認(rèn)存儲(chǔ)引擎是Overlay2。需要注意的是:不同的存儲(chǔ)引擎是需要文件系統(tǒng)支持的!
2.2 Docker層的實(shí)現(xiàn)
構(gòu)建docker鏡像時(shí)一般使用dockerfile的方式(也可以在容器里面修改,然后commit成新的鏡像,前者可以看到具體的實(shí)現(xiàn),后者除了作者,沒人知道如何實(shí)現(xiàn)的,所以一般使用前者的方式),而docker的每行命令,都會(huì)生成一個(gè)層,即使沒做什么事。在寫dockerfile時(shí),要避免生成很多層,因?yàn)槭褂么鎯?chǔ)引擎在進(jìn)行文件查找時(shí),會(huì)遍歷層,會(huì)消耗性能
docker的鏡像層和容器層如圖所示:
Image layers是base image層,該層是不可改動(dòng)的(例子中是ubuntu:鏡像),是靜態(tài)的(理解為是不會(huì)發(fā)生變化的);
當(dāng)我們基于image layer運(yùn)行容器時(shí)(比如基于ubuntu:鏡像運(yùn)行容器),Docker會(huì)創(chuàng)建一個(gè)讀寫層,也就是圖中的Container layer,該讀寫層位于所有層的最上面。
我們對(duì)容器的更改操作都會(huì)在該讀寫層中,當(dāng)我們執(zhí)行 docker commit 命令去保存我們的改動(dòng),生成新的鏡像時(shí),就相當(dāng)于給該讀寫層copy了一下,放到了Image layers中了
2.3 Docker實(shí)現(xiàn)文件的增刪改
2.3.1 copy-on-write寫時(shí)復(fù)制策略
我們首先需要了解Docker中使用的copy-on-write策略,該策略不是docker設(shè)計(jì)出的,而是最初沿用AUFS存儲(chǔ)引擎的策略,該部分的內(nèi)容見Docker的老存儲(chǔ)引擎AUFS
2.3.2 allocate-on-demand用時(shí)分配
用時(shí)分配是應(yīng)用在原本沒有該文件的場景,只有在新寫入一個(gè)文件時(shí)才分配空間,這樣可以提高存儲(chǔ)資源的利用率。比如:啟動(dòng)一個(gè)容器時(shí),并不會(huì)為這個(gè)容器預(yù)分配一些磁盤空間,只有當(dāng)新文件寫入時(shí),才按需分配新空間
如此設(shè)計(jì)的好處
- 最顯而易見的好處是減少了存儲(chǔ)空間;鏡像被分成了很多靜態(tài)可讀層,而這些層是可以共享的;當(dāng)基于本地一個(gè)已有的鏡像去構(gòu)建一個(gè)新的鏡像時(shí),只需要添加新的層,原有的層可以直接使用
- 啟動(dòng)容器變得輕量快速,因?yàn)閱?dòng)容器時(shí),只是在已有的層上添加了一層讀寫層,其他層都是用到的時(shí)候才會(huì)去搜索,遵循copy-on-write原則
三. Docker存儲(chǔ)引擎之Overlay2詳細(xì)過程
本節(jié)內(nèi)容是我想寫這篇文章的主要原因,前面介紹AUFS主要是因?yàn)樵撜撐氖?017年SEC會(huì)議收集的,那時(shí)候docker還是使用的AUFS引擎,現(xiàn)在docker已經(jīng)默認(rèn)使用Overlay2了,但是對(duì)于核心的思想,都是一樣的。下面這一部分會(huì)以一個(gè)具體的例子來介紹docker存儲(chǔ)中的一些id的作用,以及image是如何和layer映射到一起的。實(shí)驗(yàn)步驟如下:
1.拉取一個(gè)鏡像,并基于鏡像啟動(dòng)一個(gè)容器,這里以jenkins/jenkins為例子(選擇該鏡像是因?yàn)橹笠胘enkins跑CI),大家做測試可以選擇busybox
2.查看容器的ID,是為了去找到對(duì)應(yīng)的layer層
root@VM-0-3-ubuntu:/home/ubuntu# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 39274f2825c4 jenkins/jenkins "/sbin/tini -- /usr/…" 23 hours ago Up 23 hours 0.0.0.0:8080->8080/tcp, 50000/tcp test可以看到容器的ID是39274f2825c4
3.查看鏡像ID,是為了該鏡像的元數(shù)據(jù),即該鏡像包含哪些layer層
root@VM-0-3-ubuntu:/home/ubuntu# docker images REPOSITORY TAG IMAGE ID CREATED SIZE jenkins/jenkins latest 13e2b551515d 3 days ago 717MB我們可以看到鏡像的ID是13e2b551515d
4.到 /var/lib/docker/image/overlay2/imagedb/content/sha256 目錄下找到對(duì)應(yīng)鏡像文件的元數(shù)據(jù)(這里是用Step3找到的鏡像ID),cat該文件,并找到rootfs部分的diff_ids
cat ${Image_Id}| python -m json.tool | grep rootfs -A 50"rootfs": {"diff_ids": ["sha256:7948c3e5790c6df89fe48041fabd8f1c576d4bb7c869183e03b9e3873a5f33d9","sha256:4d1ab3827f6b69f4e55bd69cc8abe1dde7d7a7f61bd6e32c665f12e0a8efd1c9",........"sha256:f7e3a65f50c8e650b07c6ea2e2486852543ae281a680cb3b71f05b4a58118cb4"],"type": "layers"}這里一共有20層,我將中間的一些層去掉了,但是不妨礙分析。最上面的7948c3e5...是Image的layer層的底層,那既然找到了diff_id,我們?cè)偃タ聪耹ayer層的實(shí)現(xiàn)
5.在/var/lib/docker/image/overlay2/layerdb/sha256目錄下去查看layer信息(sha256目錄保存的是可讀層的信息,mount目錄保存的讀寫層的信息)
root@VM-0-3-ubuntu:/var/lib/docker/image/overlay2/layerdb/sha256# ls -la total 92 drwxr-xr-x 23 root root 4096 Nov 14 10:25 . drwx------ 5 root root 4096 Nov 13 10:54 .. drwx------ 2 root root 4096 Nov 13 12:44 0277e531f0f0767896e5e3c953a44bac7d46a1595ea9e1a461257d9664868be6 #此處去掉了一些層 drwx------ 2 root root 4096 Nov 11 14:06 7948c3e5790c6df89fe48041fabd8f1c576d4bb7c869183e03b9e3873a5f33d9我們可以看到,僅僅只能找到7948c3e579...這個(gè)Image的底層,其他的layer在這個(gè)目錄下都找不到,這是為什么呢?
這是由于Docker使用了chainID來保存layer,計(jì)算公式是:chainID=sha256sum(H(chainID) diffid),其中如果是最底層layer,那么其chainID=diff_id。所以在sha256目錄下,我們只會(huì)看到Image的最底層layer,而看不到其他的layer。 (sha256下的目錄是以chainID命名的,而不是以diff_id命名的,所以需要轉(zhuǎn)換一下)
6.計(jì)算下7948c3e579...下一層的chainID
root@VM-0-3-ubuntu:/var/lib/docker/image/overlay2/layerdb/sha256# echo -n "sha256:7948c3e5790c6df89fe48041fabd8f1c576d4bb7c869183e03b9e3873a5f33d9 sha256:4d1ab3827f6b69f4e55bd69cc8abe1dde7d7a7f61bd6e32c665f12e0a8efd1c9" | sha256sum 72df91e735ae2b70a23f1770aa365b67f4772a545ed0a23d3decc7643b21a4e4 -可以看到下一層的chainID是72df91e735........,這樣我們能從layerdb/sha256找到對(duì)應(yīng)的下一層了,依次類推,我們能知道所有的層級(jí)結(jié)構(gòu);
目錄下的layerdb目錄中保存的是元數(shù)據(jù),那么我們需要到overlay2目錄中去找到對(duì)應(yīng)的真實(shí)目錄,那么這個(gè)之間的映射關(guān)系是怎么得到的呢?
這個(gè)時(shí)候cache-id就排上用場了,我們可以打印出該chainID的cache-id,并到overlay2目錄中去找(dockr會(huì)創(chuàng)建/var/lib/docker/{存儲(chǔ)引擎名稱}老保存實(shí)際的數(shù)據(jù))
#到最底層7948c3e579...中打印cache-id root@VM-0-3-ubuntu:/var/lib/docker/image/overlay2/layerdb/sha256/7948c3e5790c6df89fe48041fabd8f1c576d4bb7c869183e03b9e3873a5f33d9# cat cache-id cecf9979915e13912ed6cba6dbf22d622c4c59e645fe57ce37a76f5e098363c6#到/var/lib/dockr/overlay2中找到對(duì)應(yīng)的目錄 root@VM-0-3-ubuntu:/var/lib/docker/overlay2# ls -la | grep cecf9979915e13912ed6cba6dbf22 drwx------ 3 root root 4096 Nov 11 14:06 cecf9979915e13912ed6cba6dbf22d622c4c59e645fe57ce37a76f5e098363c6可以看到已經(jīng)找到對(duì)應(yīng)的目錄了,該目錄中記錄了所有的diff
8.在Step2中找到的容器ID的元數(shù)據(jù)其實(shí)是保存在/var/lib/docker/image/overlay2/layerdb/mount/目錄下,該目錄保存的是docker的容器讀寫層。這其實(shí)也對(duì)應(yīng)了docker的存儲(chǔ)實(shí)現(xiàn)機(jī)制,鏡像都是只讀層,當(dāng)運(yùn)行一個(gè)容器時(shí),會(huì)產(chǎn)生一個(gè)容器層,該層即是讀寫層。
root@VM-0-3-ubuntu:/var/lib/docker/image/overlay2/layerdb/mounts# ls -la drwxr-xr-x 2 root root 4096 Nov 13 10:54 39274f2825c4ac012eb08ffc7fe7b383ab2f7ccda0f7fd1fd046b235d32d8a93查看該目錄下的文件
root@VM-0-3-ubuntu:/var/lib/docker/image/overlay2/layerdb/mounts/39274f2825c4ac012eb08ffc7fe7b383ab2f7ccda0f7fd1fd046b235d32d8a93# ls -l total 12 -rw-r--r-- 1 root root 69 Nov 13 10:54 init-id -rw-r--r-- 1 root root 64 Nov 13 10:54 mount-id -rw-r--r-- 1 root root 71 Nov 13 10:54 parentinit-id 和 mount-id里面的內(nèi)容基本一樣,都是記錄該容器層的cache-id,用來映射overlays目錄下真實(shí)的存儲(chǔ)層
parent文件是記錄上一層的layer層,里面記錄的chainID
四. 參考資料
因?yàn)樽畛踔皇菍⒅R(shí)記錄在自己的有道云上,因此有部分網(wǎng)上的資料忘記了存儲(chǔ)鏈接,若有兄弟發(fā)現(xiàn)自己寫的文章被我引用了,請(qǐng)聯(lián)系我刪除或者補(bǔ)鏈接!
參考資料如下:
Docker存儲(chǔ)驅(qū)動(dòng)之--overlay2
總結(jié)
以上是生活随笔為你收集整理的docker修改镜像的存储位置_Docker存储原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 肖邦夜曲21_原装进口 | 肖邦夜曲全集
- 下一篇: 华为5ipro详细参数使用功能_详细讲解