理解映象層
解釋
正如您在 什麼是映象? 中瞭解到的,容器映象由層組成。每個層一旦建立就是不可變的。但這到底意味著什麼?這些層是如何用於建立容器可以使用的檔案系統的?
映象層
映象中的每個層都包含一組檔案系統更改——新增、刪除或修改。讓我們看一下一個理論上的映象
- 第一層添加了基本命令和包管理器,例如 apt。
- 第二層安裝了 Python 執行時和用於依賴項管理的 pip。
- 第三層複製了應用程式特定的 requirements.txt 檔案。
- 第四層安裝了該應用程式特定的依賴項。
- 第五層複製了應用程式的實際原始碼。
此示例可能如下所示


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


層允許您透過重用他人的基礎層來擴充套件映象,只新增您的應用程式需要的那些資料。
堆疊層
分層是透過內容定址儲存和聯合檔案系統實現的。雖然這會變得很技術性,但以下是其工作原理
- 每個層下載後,都會解壓縮到主機檔案系統上的其自身目錄中。
- 當您從映象執行容器時,會建立一個聯合檔案系統,其中層彼此疊加,從而建立一個新的統一檢視。
- 當容器啟動時,其根目錄被設定為該統一目錄的位置,使用
chroot
。
當建立聯合檔案系統時,除了映象層外,還會專門為正在執行的容器建立一個目錄。這允許容器進行檔案系統更改,同時保持原始映象層不變。這使您可以從同一個底層映象執行多個容器。
試一試
在本實踐指南中,您將使用 docker container commit
命令手動建立新的映象層。請注意,您很少會以這種方式建立映象,因為您通常會 使用 Dockerfile。但是,它使您更容易理解其工作原理。
建立一個基礎映象
在第一步中,您將建立您自己的基礎映象,然後在後續步驟中使用它。
下載並安裝 Docker Desktop。
在終端中,執行以下命令啟動一個新的容器
$ docker run --name=base-container -ti ubuntu
映象下載完畢且容器啟動後,您應該會看到一個新的 shell 提示符。這是在容器內部執行的。它看起來類似於以下內容(容器 ID 會有所不同)
root@d8c5ca119fcd:/#
在容器內部,執行以下命令來安裝 Node.js
$ apt update && apt install -y nodejs
當此命令執行時,它會在容器內部下載並安裝 Node。在聯合檔案系統的上下文中,這些檔案系統更改發生在特定於此容器的目錄中。
透過執行以下命令驗證 Node 是否已安裝
$ node -e 'console.log("Hello world!")'
然後您應該在控制檯中看到“Hello world!”。
現在您已經安裝了 Node,可以將您所做的更改儲存為新的映象層,然後從中啟動新的容器或構建新的映象。為此,您將使用
docker container commit
命令。在新的終端中執行以下命令$ docker container commit -m "Add node" base-container node-base
使用
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。
為了證明您的映象已安裝 Node,您可以使用此新映象啟動一個新的容器
$ docker run node-base node -e "console.log('Hello again')"
這樣,您應該在終端中獲得“Hello again”輸出,表明 Node 已安裝並正常工作。
現在您已經建立了基礎映象,可以刪除該容器
$ docker rm -f base-container
基礎映象定義
基礎映象是構建其他映象的基礎。可以使用任何映象作為基礎映象。但是,某些映象是專門建立為構建塊,為應用程式提供基礎或起點。
在此示例中,您可能不會部署此
node-base
映象,因為它目前還沒有實際執行任何操作。但它是您可以用於其他構建的基礎。
構建一個應用程式映象
現在您有了基礎映象,可以擴充套件該映象來構建其他映象。
使用新建立的 node-base 映象啟動一個新的容器
$ docker run --name=app-container -ti node-base
在此容器內,執行以下命令建立一個 Node 程式
$ echo 'console.log("Hello from an app")' > app.js
要執行此 Node 程式,您可以使用以下命令,並檢視螢幕上列印的訊息
$ node app.js
在另一個終端中,執行以下命令將此容器的更改儲存為新映象
$ docker container commit -c "CMD node app.js" -m "Add app" app-container sample-app
此命令不僅建立了一個名為
sample-app
的新映象,而且還向映象添加了其他配置,以便在啟動容器時設定預設命令。在這種情況下,您將其設定為自動執行node app.js
。在容器外部的終端中,執行以下命令檢視更新後的層
$ 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
最後,使用全新的映象啟動一個新的容器。由於您指定了預設命令,因此您可以使用以下命令
$ docker run sample-app
您應該在終端中看到您的問候語出現,來自您的 Node 程式。
現在您已完成容器,可以使用以下命令刪除它們
$ docker rm -f app-container
其他資源
如果您想深入瞭解您所學到的內容,請檢視以下資源
下一步
正如前面所暗示的,大多數映象構建不使用 docker container commit
。相反,您將使用 Dockerfile,它會自動執行這些步驟。