理解映象層

解釋

正如您在 什麼是映象? 中瞭解到的,容器映象由層組成。每個層一旦建立就是不可變的。但這到底意味著什麼?這些層是如何用於建立容器可以使用的檔案系統的?

映象層

映象中的每個層都包含一組檔案系統更改——新增、刪除或修改。讓我們看一下一個理論上的映象

  1. 第一層添加了基本命令和包管理器,例如 apt。
  2. 第二層安裝了 Python 執行時和用於依賴項管理的 pip。
  3. 第三層複製了應用程式特定的 requirements.txt 檔案。
  4. 第四層安裝了該應用程式特定的依賴項。
  5. 第五層複製了應用程式的實際原始碼。

此示例可能如下所示

screenshot of the flowchart showing the concept of the image layers

這很有益,因為它允許在映象之間重用層。例如,假設您想建立另一個 Python 應用程式。由於分層,您可以利用相同的 Python 基礎。這將使構建速度更快,並減少分發映象所需的儲存空間和頻寬。映象分層可能類似於以下內容

screenshot of the flowchart showing the benefits of the image layering

層允許您透過重用他人的基礎層來擴充套件映象,只新增您的應用程式需要的那些資料。

堆疊層

分層是透過內容定址儲存和聯合檔案系統實現的。雖然這會變得很技術性,但以下是其工作原理

  1. 每個層下載後,都會解壓縮到主機檔案系統上的其自身目錄中。
  2. 當您從映象執行容器時,會建立一個聯合檔案系統,其中層彼此疊加,從而建立一個新的統一檢視。
  3. 當容器啟動時,其根目錄被設定為該統一目錄的位置,使用 chroot

當建立聯合檔案系統時,除了映象層外,還會專門為正在執行的容器建立一個目錄。這允許容器進行檔案系統更改,同時保持原始映象層不變。這使您可以從同一個底層映象執行多個容器。

試一試

在本實踐指南中,您將使用 docker container commit 命令手動建立新的映象層。請注意,您很少會以這種方式建立映象,因為您通常會 使用 Dockerfile。但是,它使您更容易理解其工作原理。

建立一個基礎映象

在第一步中,您將建立您自己的基礎映象,然後在後續步驟中使用它。

  1. 下載並安裝 Docker Desktop。

  2. 在終端中,執行以下命令啟動一個新的容器

    $ docker run --name=base-container -ti ubuntu
    

    映象下載完畢且容器啟動後,您應該會看到一個新的 shell 提示符。這是在容器內部執行的。它看起來類似於以下內容(容器 ID 會有所不同)

    root@d8c5ca119fcd:/#
    
  3. 在容器內部,執行以下命令來安裝 Node.js

    $ apt update && apt install -y nodejs
    

    當此命令執行時,它會在容器內部下載並安裝 Node。在聯合檔案系統的上下文中,這些檔案系統更改發生在特定於此容器的目錄中。

  4. 透過執行以下命令驗證 Node 是否已安裝

    $ node -e 'console.log("Hello world!")'
    

    然後您應該在控制檯中看到“Hello world!”。

  5. 現在您已經安裝了 Node,可以將您所做的更改儲存為新的映象層,然後從中啟動新的容器或構建新的映象。為此,您將使用 docker container commit 命令。在新的終端中執行以下命令

    $ docker container commit -m "Add node" base-container node-base
    
  6. 使用 docker image history 命令檢視您的映象的層

    $ docker image history node-base
    

    您將看到類似於以下內容的輸出

    IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
    d5c1fca2cdc4   10 seconds ago   /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG RELEASE                  0B
    

    請注意頂行上的“Add node”註釋。此層包含您剛剛安裝的 Node.js。

  7. 為了證明您的映象已安裝 Node,您可以使用此新映象啟動一個新的容器

    $ docker run node-base node -e "console.log('Hello again')"
    

    這樣,您應該在終端中獲得“Hello again”輸出,表明 Node 已安裝並正常工作。

  8. 現在您已經建立了基礎映象,可以刪除該容器

    $ docker rm -f base-container
    

基礎映象定義

基礎映象是構建其他映象的基礎。可以使用任何映象作為基礎映象。但是,某些映象是專門建立為構建塊,為應用程式提供基礎或起點。

在此示例中,您可能不會部署此 node-base 映象,因為它目前還沒有實際執行任何操作。但它是您可以用於其他構建的基礎。

構建一個應用程式映象

現在您有了基礎映象,可以擴充套件該映象來構建其他映象。

  1. 使用新建立的 node-base 映象啟動一個新的容器

    $ docker run --name=app-container -ti node-base
    
  2. 在此容器內,執行以下命令建立一個 Node 程式

    $ echo 'console.log("Hello from an app")' > app.js
    

    要執行此 Node 程式,您可以使用以下命令,並檢視螢幕上列印的訊息

    $ node app.js
    
  3. 在另一個終端中,執行以下命令將此容器的更改儲存為新映象

    $ docker container commit -c "CMD node app.js" -m "Add app" app-container sample-app
    

    此命令不僅建立了一個名為 sample-app 的新映象,而且還向映象添加了其他配置,以便在啟動容器時設定預設命令。在這種情況下,您將其設定為自動執行 node app.js

  4. 在容器外部的終端中,執行以下命令檢視更新後的層

    $ docker image history sample-app
    

    然後您將看到類似於以下內容的輸出。請注意頂層註釋為“Add app”,下一層為“Add node”

    IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
    c1502e2ec875   About a minute ago   /bin/bash                                       33B       Add app
    5310da79c50a   4 minutes ago        /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago          /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG RELEASE                  0B
    
  5. 最後,使用全新的映象啟動一個新的容器。由於您指定了預設命令,因此您可以使用以下命令

    $ docker run sample-app
    

    您應該在終端中看到您的問候語出現,來自您的 Node 程式。

  6. 現在您已完成容器,可以使用以下命令刪除它們

    $ docker rm -f app-container
    

其他資源

如果您想深入瞭解您所學到的內容,請檢視以下資源

下一步

正如前面所暗示的,大多數映象構建不使用 docker container commit。相反,您將使用 Dockerfile,它會自動執行這些步驟。