一般咱們在使用集羣或者容器的時候,都會接觸到存儲在本地的鏡像,也或多或少對本地鏡像存儲有必定的瞭解。可是服務端的鏡像存儲細節呢?本文主要介紹容器鏡像的服務端存儲結構,對於自建鏡像服務或是對容器鏡像底層原理或優化有興趣的同窗能夠了解一下。html
目前容器鏡像服務相關的開源項目主要有如下兩個。git
Registry具備基本的鏡像上傳、下載以及對接第三方鑑權的能力。Harbor則基於Registry作了相應的企業級擴展的項目。提供了更多權限、審計、鏡像等功能,目前是CNCF孵化項目之一。其餘詳情參考相關文章。這篇文章主要講解Registry項目的存儲細節。github
在瞭解服務端以前,咱們來了解一下客戶端的鏡像容器的存儲環境。docker
Docker的存儲驅動的實現是基於UnionFS。簡單列舉一下UnionFS下存儲鏡像的一些特色。json
首先,UnionFS是一個分層的文件系統。一個Docker鏡像可能有多個層組成(注意他們是有順序的)。api
其次,只有頂層是可寫的,其它層都是隻讀的。這樣的機制帶來的好處是鏡像層能夠被多個鏡像共享。對於Docker鏡像來講,全部層都是隻讀的。當一個鏡像運行時,會在該鏡像上增長一個容器層。十個相同的鏡像啓動,僅僅是增長十個容器層。銷燬容器時也僅僅是銷燬一個容器層而已。安全
由此能夠思考不少安全和鏡像優化上的問題。app
UnionFS通常有兩種實現方案:1. 基於文件實現。文件總體的覆蓋重寫。2. 基於塊實現,對文件的修改只修改少許塊。優化
提供一個鏡像元信息(manifest)用於參考:spa
➜ ~ docker pull ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c7b1c981c: Pulling from paas/service-controllerDigest: sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419Status: Image is up to date for ccr.ccs.tencentyun.com/paas/service-controller:7b1c981cccr.ccs.tencentyun.com/paas/service-controller:7b1c981c
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 4671, "digest": "sha256:785f4150a5d9f62562f462fa2d8b8764df4215f0f2e3a3716c867aa31887f827" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 44144090, "digest": "sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 529, "digest": "sha256:d1072db285cc5eb2f3415891381631501b3ad9b1a10da20ca2e932d7d8799988" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 849, "digest": "sha256:858453671e6769806e0374869acce1d9e5d97f5020f86139e0862c7ada6da621" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 170, "digest": "sha256:3d07b1124f982f6c5da7f1b85a0a12f9574d6ce7e8a84160cda939e5b3a1faad" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 8461461, "digest": "sha256:994dade28a14b2eac1450db7fa2ba53998164ed271b1e4b0503b1f89de44380c" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 22178452, "digest": "sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f" }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 22178452, "digest": "sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f" } ]}
*接下來是本文最爲重要的內容,經過對上面這張圖的理解,咱們就能夠了解到Registry服務端存儲的細節。*
link
文件的內容都是一個sha256的哈希值。data
文件存儲了真正的元文件和鏡像層。整個圖是從上往下的。舉個例子,咱們上面描述的manifest若是是存儲在服務端的話(文件哈希:sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419
)。它存儲的路徑應該是:/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data
。對應圖上應該是沿着左側一直向下。
咱們開始拆解分析其結構細節。
sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451
的存儲位置,應該在/docker/registry/v2/blobs/sha256/e8/e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451/data
_layers
、_manifests
兩個部分_layers
負責記錄該倉庫引用了哪些鏡像層文件。_manifests
負責記錄鏡像的元信息revisions
包含了倉庫下曾經上傳過的全部版本的鏡像元信息tags
包含了倉庫中的全部標籤current
記錄了當前標籤指向的鏡像index
目錄則記錄了標籤指向的歷史鏡像。sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419
,這個元信息的存儲位置應該在/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data
舉個鏡像下載的例子:
咱們想要知道ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c
這個鏡像如今的元信息,如何在服務端存儲中找到。
/docker/registry/v2/paas/service-controller/_manifests/tags/7b1c981c/current/link
文件。裏面有元信息的sha256信息。內容應該是sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419
/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data
)。前文中給出了該文件的json內容。sha256:785f4150a5d9f62562f462fa2d8b8764df4215f0f2e3a3716c867aa31887f827
sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451 sha256:d1072db285cc5eb2f3415891381631501b3ad9b1a10da20ca2e932d7d8799988 sha256:858453671e6769806e0374869acce1d9e5d97f5020f86139e0862c7ada6da621 sha256:3d07b1124f982f6c5da7f1b85a0a12f9574d6ce7e8a84160cda939e5b3a1faad sha256:994dade28a14b2eac1450db7fa2ba53998164ed271b1e4b0503b1f89de44380c sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f
Tips:
根據UnionFS的特性,針對性的進行優化:
須要,在Registry的設計中倉庫是權限的最小單位,用戶是根據倉庫進行權限管理與隔離的。考慮若是這裏忽略了這一塊的設計,鏡像層存在就避免重複上傳的話,客戶端能夠經過構造虛假鏡像元信息的方式,越權獲取到其餘用戶的鏡像。_layers
中記錄了倉庫有權限獲取的全部鏡像層的目的就在於此。
複製鏡像的場景和上傳場景的區別在於,源鏡像是用戶確實已經擁有的。這裏能夠經過上述問題的思考進行復制的優化,當鏡像層在目的地址已經存在時,直接標記倉庫擁有該層避免沒必要要的上傳。
根據存儲結構的特色,能夠較爲輕鬆的回答這個問題。理論上只要不作Registry GC,不刪除倉庫元信息,倉庫歷史版本的鏡像都會在倉庫中一直保存的。
這裏不作詳細講解了,有興趣的同窗能夠參考如下文檔:
雲服務的存儲對接
Registry做爲一個開源軟件,適配各類雲存儲產品屬於標配功能了。Registry提供了標準的存儲驅動接口,只要實現了這一套接口就能適配運行起來了。
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!
![]()