docker映象儲存詳解
映象來源
映象需要存在於本地倉庫中才能用其啟動容器,映象通常有以下三種來源:
l 使用dockerfile構建
l 匯入從其它倉庫save的映象
l 從遠端倉庫pull映象
其它還有對容器進行commit等,但它們的原理都包含在了以上3種方式之中。
無論採用哪種方式,映象的最初來源一般都是通過dockerfile構建而來,因此首先分析dockerfile構建映象的過程,進而幫助我們瞭解映象是如何儲存和使用的.
docker可以採用不同的儲存驅動來儲存和使用映象,目前內建的驅動有:
我們採用的是overlay2,以此為例進行分析的講解,基本原理大同小異。
關係概念:
diffID:映象每層次內容的摘要,反映了單個層次內容的資訊
chainID:映象每層次的鏈ID,演算法為H(N)=H(N-1)sha256(n),與其自身和所有的父層次相關,反映了祖先鏈。映象層次的重用需要chainID相同,如果只是diffID相同則不能命中。
cacheID:映象內容實際存放的位置,是一個隨機值,與chainID的對應關係見下面的目錄說明
目錄結構
docker的根工作目錄一般是/var/lib/docker
首先看一下涉及到的相關目錄:
/var/lib/docker/image/<graphdriver>:儲存映象管理資料的目錄,以使用的儲存驅動命名
/distribution:pull的映象相關元資料
/imagedb:映象資料庫
/content:構成映象的每層次的配置資料
/sha256/<IMAGE-ID>:每映象層次的配置digest,也就是映象ID.(參考原始碼:github.com/docker/docker/image/store.go:store.Create(config[]byte)(ID, error))
/metadata:
/sha256/<IMAGE-ID>:具有父映象的層次ID,沒有父映象的基礎映象在此目錄沒有內容
/parent:父映象ID(參考原始碼
/layerdb:映象每layer元資料
/sha256
/<chainID>:每個layer的chainID
/cache-id:本layer在下面所對應的cache-id
/diff:本層次的diffID
/size:本層次的大小
/parent:父layer chainID (moby/daemon/commit.go:Daemon.Commitmoby/layer/ro_layer.go:storeLayer)
/mounts:容器的RW layer資訊
/<container-id>:
/init-id:讀寫層的cache-id
/cache-id:容器的讀寫層mount-id
/parent:父layer的chainID
/var/lib/docker/<graphdriver>:映象的所有layer和容器rwlayer的位置
/l:符號連結目錄,每一個符號連結檔案連結向下面的cache-id,一一對應,使用這個符號連結的目的是因為mount args最大限制為一個pagesize.
/cache-id:layer的cache-id為一個隨機值.(參考原始碼:moby/layer/layer_unix.go:layerStore.mountID(namestring)string)
/diff:本layer所包含的實際檔案系統資料
link:儲存本cache-id所對應的符號連結
lower:本layer的所有父layer所對應的符號連結
/megerd:本layer及所有父layer共同呈現的目錄
/work:overlay2檔案系統使用的目錄(參考原始碼:moby/daemon/graphdriver/overlay2/overlay.go:Driver.CreateReadWrite(id,parent,opts)error)
/cache-id-init:容器的init層目錄:(moby/layer/layer_store.go:layerStore.initMount(graphID, parent, mountLabel,initFunc,storageOpt)(string,error))
映象構建
映象匯出
使用docker save命令匯出映象
映象內容:
.
├──816c0fa43179255d36592e0ede6ed020793130645eaf063fa27c5544ae46bb6b
│ ├── json
│ ├── layer.tar
│ └── VERSION
├──b8efb18f159bd948486f18bd8940b56fd2298b438229f5bd2bcf4cedcf037448.json
├── bcb8dea8dbd93bef252214259890b19a6a4886bc333d0b16f98a40b5fd063c27
│ ├── json
│ ├── layer.tar
│ └── VERSION
├──e1a9983e063a540bd4072c352ab6bc72b63ceebf311255e9d16de34eee018471
│ ├── json
│ ├── layer.tar
│ └── VERSION
└── manifest.json
b8efb18f159bd948486f18bd8940b56fd2298b438229f5bd2bcf4cedcf037448.json:
<IMAGE-ID>.json:映象配置
manifest.json:清單檔案
type manifestItem struct { Config string RepoTags []string Layers []string Parent image.ID `json:",omitempty"` LayerSources map[layer.DiffID]distribution.Descriptor `json:",omitempty"` } |
816c0fa43179255d36592e0ede6ed020793130645eaf063fa27c5544ae46bb6b:
映象每一層次的內容,這個ID是在匯出時用原有層次資訊生成的臨時映象所做的摘要。對應清單檔案中的Layers.(參考程式碼:docker/docker/image/tarexport/save.go)
json: V1Image結構體
VERSION:版本資訊,1.0
layer.tar:實際的檔案系統內容
映象匯入
映象匯出的逆過程。
參考程式碼:(image/tarexport/load.go:Load)
1. 建立臨時目錄(/tmp/XRFMG/docker-import-),對映象壓縮包進行解壓.
2. 讀取manifest.json檔案,獲取config檔名,檔名為<IMAGE-ID>.json
3. 從配置檔案中獲取所有層的diffIDS,遍歷所有diffIDS,依次載入
如果layer的chainID已經存在,則不再匯入.
如果layer的chainID不存在,則匯入.
匯入後判斷匯入layer的diffID與配置檔案中是否相等,不相等則報錯.