理解映象層

解釋

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

映象層

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

  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,它可以為您自動完成這些步驟。

編寫 Dockerfile