Dockerfile生成映象的時候是如何快取的?

花米徐發表於2017-11-24

本關將講述映象構建時的快取機制希望能夠幫助大家更好地使用Dockerfile。

Dockerfile生成映象的時候是如何快取的?

 

比如我安裝一個東西耗時兩個小時,但是構建成功之後再構建一次他就很快了,說明它快取了,現在我的疑惑是如果我稍微改變了一點東西,如何保證他不需要在再耗時兩個小時。

docker build過程中每執行一步RUN命令,就生成一個映象,另外映象之間有血緣關係,是否需要重新編譯兩個小時取決於你的修改影響的第一個映象有多早。
簡單理解當你修改dockerfile,當你修改了N行的RUN命令, N+1之後的命令都要重跑;

docker image --tree #檢視映象的依賴關係

 

另外你直接docker images也能看到很多None名字的映象檔案,

那就是你之前build的結果; 如果build成功的話,就會把None改成你指定的name;

 

 

首先舉一個我平時構建Dockerfile時遇到的小例子。

我想使用Dockerfile構建一個基於centos並擁有java執行環境的映象,我的Dockerfile如下所示:

然後我使用
docker build -t javaimage:v1.0 .這條命令去構建該映象。經過長時間的下載,等待之後,映象終於構建好了,但是我突然發現,我的JAVA_HOME環境變數竟然有問題,我竟然將jre1.8.0_144寫成了jre1.8.0_14。於是我重新修改了Dockerfile檔案,然後docker build -t javaimage:v1.0 .進行構建。

令人驚喜的是,這一次構建過程一下子就完成了。好像它根本不需要重新下載jre一樣,那究竟是怎麼回事呢?下面是第二次執行docker build -t javaimage:v1.0 .的情況。可以發現,在執行RUN指令時,顯示了Using cache,也就是使用了快取的意思。就是它讓我們跳過了漫長的等待過程!那為什麼從第三步開始就沒有使用快取了呢?下面我們將詳細地講述映象構建時的快取機制。

映象構建時的快取機制

在構建映像的過程中,Docker將按照指定的順序逐步執行您的Dockerfile中的指令。隨著每條指令的檢查,Docker將在其快取中查詢可重用的現有映像,而不是建立一個新的(重複)映像。如果您不想使用快取,可以在docker build命令中使用--no-cache = true選項。但是,如果您確實讓Docker使用其快取,那麼瞭解何時會找到匹配的映像是非常重要的。

Docker將遵循的基本規則如下:

  1. 從已經在快取中的父映象開始,將下一個指令與從該基本映象匯出的所有子映象進行比較,以檢視其中一個是否使用完全相同的指令構建。如果沒有,則快取無效。
  2. 在大多數情況下,只需將Dockerfile中的指令與其中一個子映象進行比較即可(通過比較是否與上一次執行的指令一致)。但是,某些指令需要一些額外的檢查。對於ADD和COPY指令,將檢查映象中檔案的內容,併為每個檔案計算校驗和。在這些校驗和中不考慮檔案的最後修改和最後訪問的時間。在快取查詢期間,將校驗和與現有映像中的校驗和進行比較。如果檔案(如內容和後設資料)中有任何變化,則快取無效。
  3. 除了ADD和COPY命令之外,快取檢查將不會檢視容器中的檔案來確定快取匹配。例如,當處理RUN apt-get -y update命令時,不會檢查在容器中更新的檔案以確定是否存在快取記憶體命中,它將只會檢查命令字串是否與之前的一致來判斷是否匹配。

    一旦某一層的快取無效,所有後續的Dockerfile命令將生成新的映象,並且快取記憶體將不被使用。

    我想現在你應該已經明白了Dockerfile構建過程的快取機制了,希望這些知識能夠幫助你今後更好地使用Dockerfile。

    參考文獻:
    Docker官方對快取的介紹:
    https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#build-cache

相關文章