Docker 映像的運作方式

已完成

回想我們曾說過,容器映像會是我們用來散發應用程式的單位。 我們也曾提及,容器的標準化格式讓開發人員和作業小組都可使用。

現在,我們將來探討 Docker 中所使用軟體、套件及映像之間的差異。 了解這些概念間的差異,將可協助我們進一步了解 Docker 映像的運作方式。

我們也將簡短討論在主機上執行的 OS 角色,以及在容器中執行的 OS 角色。

封裝到容器的軟體

封裝到容器的軟體不限於我們開發人員所建置的應用程式。 當我們談論軟體時,我們指的是在容器中執行的應用程式程式碼、系統套件、二進位檔、程式庫、設定檔及作業系統。

例如,假設我們正在開發訂單追蹤入口網站,以供公司的各個暢貨中心使用。 我們需要查看將執行 Web 應用程式的完整軟體堆疊。 我們所建置的應用程式是 .NET Core MVC 應用程式,並規劃使用 Nginx 來部署應用程式,以作為 Ubuntu Linux 上的反向 Proxy 伺服器。 所有這些軟體元件都會形成容器映像的一部分。

什麼是容器映像?

容器映像是包含軟體的可攜式套件。 正是這個映像會在執行時成為我們的容器。 容器是映像的記憶體內部執行個體。

容器映像是不可變的。 建置映射之後,就無法加以變更。 變更映像的唯一方式就是建立新映像。 此功能保證我們在實際執行環境中所使用的映像,與在開發和 QA 中所使用的映像相同。

什麼是主機 OS?

主機 OS 是 Docker 引擎執行所在的 OS。 在 Linux 上執行的 Docker 容器會分享主機 OS 核心,而且只要二進位檔可以直接存取 OS 核心,就不需要容器 OS。

Diagram showing a Docker image with no base OS and the dependency on the host OS Kernel.

不過,Windows 容器需要容器 OS。 容器相依於 OS 核心來管理如下的服務:檔案系統、網路管理、處理排程及記憶體管理。

什麼是容器 OS?

容器 OS 是屬於已封裝映像一部分的 OS。 我們可以在容器中彈性地包含不同版本的 Linux 或 Windows 作業系統。 我們能利用這種彈性,存取特定的 OS 功能,或安裝應用程式可能會用到的其他軟體。

Diagram showing a Docker image with an Ubuntu base OS and the dependency on the host OS Kernel.

容器 OS 與主機 OS 相隔離,而且是我們部署及執行應用程式的環境所在。 與映像的不變性相結合,此隔離表示應用程式在開發中執行的環境與在實際執行環境中的運作方式相同。

在我們的範例中,會使用 Ubuntu Linux 作為容器 OS,而此 OS 不會因為開發或實際執行而變更。 我們使用的映像一律相同。

什麼是可堆疊的統一檔案系統 (Unionfs)?

我們會用 Unionfs 來建立 Docker 映像。 Unionfs 是一種檔案系統,可讓您堆疊數個稱為分支的目錄,讓它看起來像是合併了內容一樣。 不過,內容實際上會保持獨立。 當您建置檔案系統時,Unionfs 可讓您新增和移除分支。

Diagram showing the stacking of layers in a Docker image created with unionfs.

例如,假設我們正在為先前的 Web 應用程式建置映像。 我們會將 Ubuntu 散發分層為開機檔案系統上方的基礎映像。 接下來,將安裝 Nginx 和我們的 Web 應用程式。 我們在原始 Ubuntu 映像上方有效地將 Nginx 和 Web 應用程式分層。

從映像執行容器之後,就會建立最後一個可寫入層。 不過,此層不會在容器終結時保存。

什麼是基礎映像?

基礎映像是使用 Docker scratch 映像的映像。 scratch 映像是空的容器映像,不會建立檔案系統層。 此映像假設您要執行的應用程式可以直接使用主機 OS 核心。

什麼是父映像?

父映像是您用來建立映像的容器映像。

例如,我們不會從 scratch 建立映像,然後安裝 Ubuntu,而是會使用已以 Ubuntu 為根據的映像。 我們甚至可以使用已安裝 Nginx 的映像。 父映像通常包含容器 OS。

基礎映像和父映像之間的主要差異為何?

這兩種映像類型都可讓我們建立可重複使用的映像。 不過,基礎映像讓我們能夠更充分掌控最終映像的內容。 回想一下先前的內容,映像是不可變的,您只能新增至映像而無法削減。

在 Windows 上,您只能建立以 Windows 基礎容器映像為基礎的容器映像。 Microsoft 提供及服務這些 Windows 基底容器映像。

什麼是 Dockerfile?

Dockerfile 是一個文字檔,其中包含我們用來建置和執行 Docker 映像的指示。 我們為映像定義了下列層面:

  • 用來建立新映像的基礎映像或父映像
  • 用來更新基底 OS 並安裝其他軟體的命令
  • 要包含的組建成品,例如開發的應用程式
  • 要公開的服務,例如儲存體和網路設定
  • 要在容器啟動時執行的命令

讓我們將這些層面對應到範例 Dockerfile。 假設我們要為 ASP.NET Core 網站建立 Docker 映像。 Dockerfile 可能如下範例所示:

# Step 1: Specify the parent image for the new image
FROM ubuntu:18.04

# Step 2: Update OS packages and install additional software
RUN apt -y update &&  apt install -y wget nginx software-properties-common apt-transport-https \
	&& wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
	&& dpkg -i packages-microsoft-prod.deb \
	&& add-apt-repository universe \
	&& apt -y update \
	&& apt install -y dotnet-sdk-3.0

# Step 3: Configure Nginx environment
CMD service nginx start

# Step 4: Configure Nginx environment
COPY ./default /etc/nginx/sites-available/default

# STEP 5: Configure work directory
WORKDIR /app

# STEP 6: Copy website code to container
COPY ./website/. .

# STEP 7: Configure network requirements
EXPOSE 80:8080

# STEP 8: Define the entry point of the process that runs in the container
ENTRYPOINT ["dotnet", "website.dll"]

我們不會在此處討論 Dockerfile 檔案規格,或上述範例中每個命令的詳細資料。 不過,請注意,此檔案中有數個命令可讓我們操作映像的結構。 例如,COPY 命令會將內容從本機電腦上的特定資料夾複製到您要建置的容器映像。

還記得之前我們提到過,Docker 映像會利用 unionfs。 當我們建置最終容器映像時,這其中每個步驟都會建立快取的容器映像。 這些暫時性映像都會分層放在前一個映像上方,並在所有步驟完成後呈現為單一映像。

最後,請注意最後一個步驟:步驟 8。 檔案中的 ENTRYPOINT 表示從映像執行容器之後,將執行哪一個處理序。 如果沒有 ENTRYPOINT 或另外一個要執行的流程,Docker 會將其解釋為容器無工作可執行,因此容器將會退出。

如何管理 Docker 映像

Docker 映像為大型檔案,一開始儲存於您的電腦上,而我們需要工具來管理這些檔案。

Docker CLI 和 Docker Desktop 可讓我們藉由建置、列出、移除和執行映像來管理它們。 我們使用 docker 用戶端來管理 Docker 映像。 此用戶端不會直接執行命令,並將所有查詢傳送至 dockerd 精靈。

我們將不會在此處討論所有用戶端命令和命令旗標,但將探討一些最常使用的命令。 本課程模組末尾的「深入了解」章節將包含 Docker 文件的連結,其中涵蓋了所有命令和命令旗標的詳細資訊。

如何建置映像

我們使用 docker build 命令來建置 Docker 映像。 假設我們使用稍早的 Dockerfile 定義來建置映像。 以下是顯示組建命令的範例:

docker build -t temp-ubuntu .

以下是建置命令所產生的輸出:

Sending build context to Docker daemon  4.69MB
Step 1/8 : FROM ubuntu:18.04
 ---> a2a15febcdf3
Step 2/8 : RUN apt -y update && apt install -y wget nginx software-properties-common apt-transport-https && wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb && add-apt-repository universe && apt -y update && apt install -y dotnet-sdk-3.0
 ---> Using cache
 ---> feb452bac55a
Step 3/8 : CMD service nginx start
 ---> Using cache
 ---> ce3fd40bd13c
Step 4/8 : COPY ./default /etc/nginx/sites-available/default
 ---> 97ff0c042b03
Step 5/8 : WORKDIR /app
 ---> Running in 883f8dc5dcce
Removing intermediate container 883f8dc5dcce
 ---> 6e36758d40b1
Step 6/8 : COPY ./website/. .
 ---> bfe84cc406a4
Step 7/8 : EXPOSE 80:8080
 ---> Running in b611a87425f2
Removing intermediate container b611a87425f2
 ---> 209b54a9567f
Step 8/8 : ENTRYPOINT ["dotnet", "website.dll"]
 ---> Running in ea2efbc6c375
Removing intermediate container ea2efbc6c375
 ---> f982892ea056
Successfully built f982892ea056
Successfully tagged temp-ubuntu:latest

如果您不了解上述輸出,請不要擔心。 不過,請注意輸出中所列的步驟。 當每個步驟執行時,就會在我們所建置的映像中新增一層。

此外,請注意,我們執行一些命令來安裝軟體和管理設定。 例如,我們在步驟 2 中執行 apt -y updateapt install -y 命令來更新 OS。 這些命令均會在為該步驟所建立的執行中容器內執行。 執行命令之後,即會移除中繼容器。 基礎快取映像會保留在組建主機上,而且不會自動刪除。 這項最佳化確保後續的組建會重複使用這些映像來加速組建時間。

什麼是映像標籤?

映像標籤是用來建立映像版本的文字字串。

在稍早的範例組建中,請注意最後一個敘述「已成功標記 temp-ubuntu: latest」的組建訊息。 建置映像時,我們會為映像命名,並選擇性地使用 -t 命令旗標來標記。 在我們的範例中,會使用 -t temp-ubuntu 來為映像命名,同時將產生的映像名稱標記為 temp-ubuntu: latest。 如果您未指定標籤,則會為映像加上 latest 標籤。

單一映像可獲指派多個標籤。 依照慣例,最新版的映像可獲指派 latest 標籤,以及描述映像版本號碼的標籤。 當您發行映像的新版本時,您可以重新指派 latest 標籤以參考新的映像。

對於 Windows,Microsoft 不會提供具有最新標籤的基礎容器映像。 對於 Windows 基礎容器映像,您必須指定要使用的標籤。 例如,Server Core 的 Windows 基礎容器映像為 mcr.microsoft.com/windows/servercore。 其標籤中包括 ltsc2016ltsc2019ltsc2022

以下是另一個範例。 假設您想要使用 .NET Core 範例 Docker 映像。 我們在此有四個平台版本可供選擇:

  • mcr.microsoft.com/dotnet/core/samples:dotnetapp

  • mcr.microsoft.com/dotnet/core/samples:aspnetapp

  • mcr.microsoft.com/dotnet/core/samples:wcfservice

  • mcr.microsoft.com/dotnet/core/samples:wcfclient

在上述映像清單中,我們可以看到 Microsoft 提供多個 .NET Core 的範例。 標籤會指定影像所參考的樣本: ASP.NET、WCF 服務等等。

如何列出映像

Docker 軟體會自動在您的電腦上設定本機映像登錄。 您可以使用 docker images 命令來檢視此登錄中的映像。

docker images

輸出看起來會像下列範例這樣:

REPOSITORY          TAG                     IMAGE ID            CREATED                     SIZE
tmp-ubuntu          latest             f89469694960        14 minutes ago         1.69GB
tmp-ubuntu          version-1.0        f89469694960        14 minutes ago         1.69GB
ubuntu              18.04                   a2a15febcdf3        5 weeks ago            64.2MB

請注意,映像會以其「名稱」、「標籤」和「映像識別碼」來列出。 您應該記得,我們可以將多個標籤套用到一個映像。 上述輸出會顯示範例;即使映射名稱不同,我們可以看到識別碼相同。

映像識別碼是可用來識別和管理名稱或標籤可能不明確之映像的實用方式。

如何移除映像

您可以使用 docker rmi 命令,從本機 Docker 登錄中移除映像。 如果您需要節省容器主機磁碟上的空間,這非常有用,因為容器映像層將會累積到可用的總空間中。

指定要移除之映像的名稱或識別碼。 此範例使用映像名稱來移除範例 Web 應用程式的映像:

docker rmi temp-ubuntu:version-1.0

如果容器仍在使用映像,您將無法移除映像。 docker rmi 命令會傳回一則錯誤訊息,其中會列出依賴該映像的容器。

我們已探討 Docker 映像的基本概念、如何管理這些映像,以及如何從映像中執行容器。 接下來,將探討如何管理容器。

檢定您的知識

1.

Docker Desktop 為適用於建置及共用容器化應用程式與微服務的應用程式,其在下列哪一個作業系統上提供使用?

2.

下列哪一項是用來重建容器映像的正確 Docker 命令?

3.

下列哪一項是描述容器映像的最佳語句?