Docker鏡像的存儲機制

近幾年 Docker 風靡技術圈,不少從業人員都或多或少使用過,也了解如何通過 Dockerfile 構建鏡像,從遠程鏡像倉庫拉取自己所需鏡像,推送構建好的鏡像至遠程倉庫,根據鏡像運行容器等。這個過程十分簡單,只需執行 docker build、docker pull、docker push、docker run 等操作即可。但大家是否想過鏡像在本地到底是如何存儲的?容器又是如何根據鏡像啟動的?推送鏡像至遠程鏡像倉庫時,服務器又是如何存儲的呢?下面我們就來簡單聊一聊。

Docker 鏡像本地存儲機制及容器啟動原理

Docker 鏡像不是一個單一的文件,而是有多層構成。我們可通過 Docker images 獲取本地的鏡像列表及對應的元信息, 接著可通過docker history <imageId> 查看某個鏡像各層內容及對應大小,每層對應著 Dockerfile 中的一條指令。Docker 鏡像默認存儲在 /var/lib/docker/<storage-driver>中,可通過 DOCKER_OPTS 或者 docker daemon 運行時指定 --graph= 或 -g 指定。

Docker 使用存儲驅動來管理鏡像每層內容及可讀寫的容器層,存儲驅動有 DeviceMapper、AUFS、Overlay、Overlay2、btrfs、ZFS 等,不同的存儲驅動實現方式有差異,鏡像組織形式可能也稍有不同,但都采用棧式存儲,并采用 Copy-on-Write(CoW) 策略。且存儲驅動采用熱插拔架構,可動態調整。那么,存儲驅動那么多,該如何選擇合適的呢?大致可從以下幾方面考慮:

  • 若內核支持多種存儲驅動,且沒有顯式配置,Docker 會根據它內部設置的優先級來選擇。優先級為 aufs > btrfs/zfs > overlay2 > overlay > devicemapper。若使用 devicemapper 的話,在生產環境,一定要選擇 direct-lvm, loopback-lvm 性能非常差。
  • 選擇會受限于 Docker 版本、操作系統、系統版本等。例如,aufs 只能用于 Ubuntu 或 Debian 系統,btrfs 只能用于 SLES (SUSE Linux Enterprise Server, 僅 Docker EE 支持)。
  • 有些存儲驅動依賴于后端的文件系統。例如,btrfs 只能運行于后端文件系統 btrfs 上。
  • 不同的存儲驅動在不同的應用場景下性能不同。例如,aufs、overlay、overlay2 操作在文件級別,內存使用相對更高效,但大文件讀寫時,容器層會變得很大;DeviceMapper、btrfs、ZFS 操作在塊級別,適合工作在寫負載高的場景;容器層數多,且寫小文件頻繁時,Overlay 效率比 Overlay2 更高;btrfs、ZFS 更耗內存。

Docker 容器其實是在鏡像的最上層加了一層讀寫層,通常也稱為容器層。在運行中的容器里做的所有改動,如寫新文件、修改已有文件、刪除文件等操作其實都寫到了容器層。容器層刪除了,最上層的讀寫層跟著也刪除了,改動自然也丟失了。若要持久化這些改動,須通過 docker commit <containerId> [repository[:tag]] 將當前容器保存成為一個新鏡像。若想將數據持久化,或是多個容器間共享數據,需將數據存儲在 Docker Volume 中,并將 Volume 掛載到相應容器中。

存儲驅動決定了鏡像及容器在文件系統中的存儲方式及組織形式,下面分別對常見的 AUFS、Overlay 作一簡單介紹。

AUFS

AUFS 簡介

AUFS 是 Debian (Stretch 之前的版本,Stretch默認采用 overlay2) 或 Ubuntu 系統上 Docker 的默認存儲驅動,也是 Docker 所有存儲驅動中最為成熟的。具有啟動快,內存、存儲使用高效等特點。如果使用的 Linux 內核版本為 4.0 或更高,且使用的是 Docker CE,可考慮使用overlay2 (比 AUFS 性能更佳)。

配置 AUFS 存儲驅動

  1. 驗證內核是否支持 AUFS
    $ grep aufs /proc/filesystems
    nodev aufs

  2. 若內核支持,可在 docker 啟動時通過指定參數 --storage-driver=aufs 選擇 AUFS

AUFS 存儲驅動工作原理

采用 AUFS 存儲驅動時,有關鏡像和容器的所有層信息都存儲在 /var/lib/docker/aufs/目錄下,下面有三個子目錄:

  • /diff:每個目錄中存儲著每層鏡像包含的真實內容
  • /layers:存儲有關鏡像層組織的元信息,文件內容存儲著該鏡像的組建鏡像列表
  • /mnt:掛載點信息存儲,當創建容器后,mnt 目錄下會多出容器對應的層及該容器的 init 層。目錄名稱與容器 Id 不一致。實際的讀寫層存儲在/var/lib/docker/aufs/diff,直到容器刪除,此讀寫層才會被清除掉。

采用 AUFS 后容器如何讀寫文件?

讀文件

容器進行讀文件操作有以下三種場景:

  • 容器層不存在: 要讀取的文件在容器層中不存在,存儲驅動會從鏡像層逐層向下找,多個鏡像層中若存在同名文件,上層的有效。
  • 文件只存在容器層:讀取容器層文件
  • 容器層與鏡像層同時存在:讀取容器層文件

修改文件或目錄

容器中進行文件的修改同樣存在三種場景:

  • 第一次寫文件:若待修改的文件在某個鏡像層中,AUFS 會先執行 copy_up 操作將文件從只讀的鏡像層拷貝到可讀寫的容器層,然后進行修改。在文件非常大的情況下效率比較低下。
  • 刪除文件:刪除文件時,若文件在鏡像層,其實是在容器層創建一個特殊的 whiteout 文件,容器層訪問不到,并沒有實際刪掉。
  • 目錄重命名:目前 AUFS 還不支持目錄重命名。

OverlayFS

OverlayFS 簡介

OverlayFS 是一種類似 AUFS 的現代聯合文件系統,但實現更簡單,性能更優。OverlayFS 嚴格說來是 Linux 內核的一種文件系統,對應的 Docker 存儲驅動為 overlay 或者 overlay2,overlay2 需 Linux 內核 4.0 及以上,overlay 需內核 3.18 及以上。且目前僅 Docker 社區版支持。條件許可的話,盡量使用 overlay2,與 overlay 相比,它的 inode 利用率更高。

容器如何使用 Overlay/Overlay2 讀寫文件

讀文件

讀文件存在以下三種場景:

  • 文件不存在容器層:若容器要讀的文件不在容器層,會繼續從底層的鏡像層找
  • 文件僅在容器層:若容器要讀的文件在容器層,直接讀取,不用在底層的鏡像層查找
  • 文件同時在容器層和鏡像層:若容器要讀的文件在容器層和鏡像層中都存在,則從容器層讀取

修改文件或目錄

寫文件存在以下三種場景:

  • 首次寫文件:若要寫的文件位于鏡像層中,則執行 copy_up 將文件從鏡像層拷貝至容器層,然后進行修改,并在容器層保存一份新的。若文件較大,效率較低。OverlayFS 工作在文件級別而不是塊級別,這意味著即使對文件稍作修改且文件很大,也須將整個文件拷貝至容器層進行修改。但需注意的是,copy_up 操作僅發生在首次,后續對同一文件進行修改,操作容器層文件即可
  • 刪除文件或目錄:容器中刪除文件或目錄時,其實是在容器中創建了一個 whiteout 文件,并沒有真的刪除文件,只是使其對用戶不可見
  • 目錄重命名:僅當源路徑與目標路徑都在容器層時,調用 rename(2) 函數才成功,否則返回 EXDEV

遠程鏡像倉庫如何存儲鏡像?

不少人可能經常使用 docker,那么有沒有思考過鏡像推送至遠程鏡像倉庫,是如何保存的呢?Docker 客戶端是如何與遠程鏡像倉庫交互的呢?

我們平時本地安裝的 docker 其實包含兩部分:docker client 與 docker engine,docker client 與 docker engine 間通過 API 進行通信。Docker engine 提供的 API 大致有認證、容器、鏡像、網絡、卷、swarm 等,具體調用形式請參考:Docker Engine API

Docker engine 與 registry (即:遠程鏡像倉庫)的通信也有一套完整的 API,大致包含 pull、push 鏡像所涉及的認證、授權、鏡像存儲等相關流程,具體請參考:Registry API。目前常用 registry 版本為 v2,registry v2 擁有斷點續傳、并發拉取鏡像多層等特點。能并發拉取多層是因為鏡像的元信息與鏡像層數據分開存儲,當 pull 一個鏡像時,先進行認證獲取到 token 并授權通過,然后獲取鏡像的 manifest 文件,進行 signature 校驗。校驗完成后,依據 manifest 里的層信息并發拉取各層。其中 manifest 包含的信息有:倉庫名稱、tag、鏡像層 digest 等, 更多,請參考:manifest 格式文檔

各層拉下來后,也會先在本地進行校驗,校驗算法采用 sha256。Push 過程則先將鏡像各層并發推至 Registry,推送完成后,再將鏡像的 manifest 推至 Registry。Registry 其實并不負責具體的存儲工作,具體存儲介質根據使用方來定,Registry 只是提供一套標準的存儲驅動接口,具體存儲驅動實現由使用方實現。

目前官方 Registry 默認提供的存儲驅動包括:微軟 Azure、Google GCS、Amazon S3、Openstack Swift、本地存儲等。若需要使用自己的對象存儲服務,則需要自行實現 Registry 存儲驅動。網易云目前將鏡像存儲在自己的對象存儲服務 NOS 上,故專門針對 NOS 實現了一套存儲驅動,另外認證服務也對接了網易云認證服務,并結合自身業務實現了一套認證、授權邏輯,并有效地限制了倉庫配額。

Registry 干的事情其實很簡單,大致可分為:1.讀配置;2.注冊handler;3.監聽。本質上 Registry 是個 HTTP 服務,啟動后,監聽在配置文件設定的某端口上。當 http 請求過來后,便會觸發之前注冊過的 handler。Handler 包含 manifest、tag、blob、blob-upload、blob-upload-chunk、catalog 等六類,具體請可參考 registry 源碼:/registry/handlers/app.go:92。配置文件包含監聽端口、auth 地址、存儲驅動信息、回調通知等。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • Docker — 云時代的程序分發方式 要說最近一年云計算業界有什么大事件?Google Compute Engi...
    ahohoho閱讀 15,591評論 15 147
  • 《Docker從入門到實踐》閱讀筆記 原書地址: https://yeasy.gitbooks.io/docker...
    GuoYuebo閱讀 11,412評論 1 39
  • 一 、什么是 Docker Docker 最初是 dotCloud 公司創始人 Solomon Hykes 在法國...
    Blazzer閱讀 3,158評論 0 13
  • 1、問題描述:原始數據創建的Tin,棱角分明,粗糙,丑,想美化一下,平滑柔和一下。2、解決方案:目前的解決方案是:...
    Higer2017閱讀 916評論 0 0
  • TOP1 身邊的朋友都愛勸我:被看又不會少一塊肉、被討厭又不會少一塊肉、幫一下又不會少一塊肉之類的。 神回復: 我...
    真椅子閱讀 307評論 0 1