將 Windows Dockerfiles 最佳化
有許多方式可將 Docker 建置程式與產生的 Docker 映射優化。 本文說明 Docker 建置程式的運作方式,以及如何以最佳方式建立 Windows 容器的映射。
Docker 組建中的映射層
您必須先知道 Docker 組建的運作方式,才能將 Docker 組建優化。 Docker 建置流程期間使用了 Dockerfile,且每個可採取動作的指令都依序在其自身的暫存容器中執行。 結果就為每個可採取動作的指令產生了新的映像層。
例如,下列範例 Dockerfile 會使用 mcr.microsoft.com/windows/servercore:ltsc2019
基底 OS 映射、安裝 IIS,然後建立簡單的網站。
# Sample Dockerfile
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
CMD [ "cmd" ]
您可能會預期此 Dockerfile 會產生具有兩層的映射、一個用於容器 OS 映射,另一個包含 IIS 和網站。 不過,實際映射有許多層,而且每個圖層都相依于其之前。
為了更清楚,讓我們對範例 Dockerfile 所建立的映射執行 docker history
命令。
docker history iis
IMAGE CREATED CREATED BY SIZE COMMENT
f4caf476e909 16 seconds ago cmd /S /C REM (nop) CMD ["cmd"] 41.84 kB
f0e017e5b088 21 seconds ago cmd /S /C echo "Hello World - Dockerfile" > c 6.816 MB
88438e174b7c About a minute ago cmd /S /C dism /online /enable-feature /all / 162.7 MB
6801d964fda5 4 months ago 0 B
輸出顯示此映射有四個層:基底層和三個額外的層,這些層會對應至 Dockerfile 中的每個指令。 底層 (此範例中為 6801d964fda5
) 代表基本 OS 映像。 一層是 IIS 安裝。 再上一層則包含新的網站,以此類推。
Dockerfiles 可以寫入以將映射層最小化、優化建置效能,以及透過可讀性將協助工具優化。 最後,有許多方式可以完成相同的映像建置工作。 瞭解 Dockerfile 的格式如何影響建置時間,以及其建立的映射可改善自動化體驗。
優化影像大小
根據您的空間需求,在建置 Docker 容器映射時,映射大小可能是一個重要因素。 容器映像在登錄和主機之間移動、進行匯出和匯入,而且最終會耗用空間。 本節將告訴您如何在 Windows 容器的 Docker 建置程式期間將映射大小降到最低。
如需 Dockerfile 最佳做法的其他資訊,請參閱 在 Docker.com 上撰寫 Dockerfiles 的最佳做法。
群組相關的動作
由於每個 RUN
指令都會在容器映射中建立新的層,因此將動作分組成一個 RUN
指令可以減少 Dockerfile 中的層數。 雖然將層最小化可能不會對映像大小造成太大的影響,但將相關聯的動作分組卻會有明顯影響,您會在後續的範例看到相關示範。
在本節中,我們將比較兩個執行相同動作的範例 Dockerfile。 不過,一個 Dockerfile 每個動作都有一個指令,而另一個則將其相關的動作分組在一起。
下列未分組的 Dockerfile 會下載適用于 Windows 的 Python、安裝它,並在安裝完成後移除下載的安裝程式檔案。 在此 Dockerfile 中,每個動作都會獲得自己的 RUN
指令。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell.exe -Command Invoke-WebRequest "https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe" -OutFile c:\python-3.5.1.exe
RUN powershell.exe -Command Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait
RUN powershell.exe -Command Remove-Item c:\python-3.5.1.exe -Force
產生出的映像包含三個額外的層,每個 RUN
指令皆有一個層。
docker history doc-example-1
IMAGE CREATED CREATED BY SIZE COMMENT
a395ca26777f 15 seconds ago cmd /S /C powershell.exe -Command Remove-Item 24.56 MB
6c137f466d28 28 seconds ago cmd /S /C powershell.exe -Command Start-Proce 178.6 MB
957147160e8d 3 minutes ago cmd /S /C powershell.exe -Command Invoke-WebR 125.7 MB
第二個範例是執行完全相同作業的 Dockerfile。 不過,所有相關動作都已分組在單 RUN
一指令之下。 指令中的每個 RUN
步驟都是在 Dockerfile 的新行上,而 '\' 字元則用來換行。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell.exe -Command \
$ErrorActionPreference = 'Stop'; \
Invoke-WebRequest https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
Remove-Item c:\python-3.5.1.exe -Force
產生的影像對於指令只有一個額外的圖層 RUN
。
docker history doc-example-2
IMAGE CREATED CREATED BY SIZE COMMENT
69e44f37c748 54 seconds ago cmd /S /C powershell.exe -Command $ErrorAct 216.3 MB
移除多餘的檔案
如果您的 Dockerfile 中有檔案,例如安裝程式,則不需要在使用它之後,您可以將其移除以減少映射大小。 這需與將檔案複製到映像層的步驟同時進行。 這樣做可防止檔案保存在較低層級的映射層中。
在下列範例 Dockerfile 中,會下載、執行、移除 Python 套件。 這全在一項 RUN
作業期間完成,並產生出單一映像層。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell.exe -Command \
$ErrorActionPreference = 'Stop'; \
Invoke-WebRequest https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \
Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \
Remove-Item c:\python-3.5.1.exe -Force
優化建置速度
多行
您可以將作業分割成多個個別指示,以優化 Docker 建置速度。 多個 RUN
作業會提高快取效率,因為會為每個 RUN
指令建立個別層。 如果已在不同的 Docker 建置作業中執行相同的指令,則會重複使用此快取作業 (映射層) ,因而導致 Docker 組建執行時間降低。
在下列範例中,會下載、安裝 Apache 和 Visual Studio 轉散發套件,然後藉由移除不再需要的檔案來清除套件。 這全都是使用單 RUN
一指令來完成。 如果更新其中任何一個動作,所有動作都會重新執行。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell -Command \
# Download software ; \
wget https://www.apachelounge.com/download/VC11/binaries/httpd-2.4.18-win32-VC11.zip -OutFile c:\apache.zip ; \
wget "https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe" -OutFile c:\vcredist.exe ; \
wget -Uri http://windows.php.net/downloads/releases/php-5.5.33-Win32-VC11-x86.zip -OutFile c:\php.zip ; \
# Install Software ; \
Expand-Archive -Path c:\php.zip -DestinationPath c:\php ; \
Expand-Archive -Path c:\apache.zip -DestinationPath c:\ ; \
Start-Process c:\vcredist.exe -ArgumentList '/quiet' -Wait ; \
# Remove unneeded files ; \
Remove-Item c:\apache.zip -Force; \
Remove-Item c:\vcredist.exe -Force; \
Remove-Item c:\php.zip
產生的映射有兩層,一個用於基底 OS 映射,另一個包含來自單 RUN
一指令的所有作業。
docker history doc-sample-1
IMAGE CREATED CREATED BY SIZE COMMENT
9bdf3a21fd41 8 minutes ago cmd /S /C powershell -Command Invoke-WebR 205.8 MB
6801d964fda5 5 months ago 0 B
相較之下,以下是分成三 RUN
個指令的相同動作。 在此情況下,每個 RUN
指令都會快取在容器映射層中,而且只有已變更的指令必須在後續的 Dockerfile 組建上重新執行。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
wget https://www.apachelounge.com/download/VC11/binaries/httpd-2.4.18-win32-VC11.zip -OutFile c:\apache.zip ; \
Expand-Archive -Path c:\apache.zip -DestinationPath c:\ ; \
Remove-Item c:\apache.zip -Force
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
wget "https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe" -OutFile c:\vcredist.exe ; \
Start-Process c:\vcredist.exe -ArgumentList '/quiet' -Wait ; \
Remove-Item c:\vcredist.exe -Force
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
wget http://windows.php.net/downloads/releases/php-5.5.33-Win32-VC11-x86.zip -OutFile c:\php.zip ; \
Expand-Archive -Path c:\php.zip -DestinationPath c:\php ; \
Remove-Item c:\php.zip -Force
產生的影像是由四個圖層所組成;基底 OS 映射的一層,以及這三 RUN
個指示中的每一層。 因為每個 RUN
指令都是在自己的層中執行,所以此 Dockerfile 的任何後續執行或不同 Dockerfile 中的相同指令集都會使用快取的映射層,以減少建置時間。
docker history doc-sample-2
IMAGE CREATED CREATED BY SIZE COMMENT
ddf43b1f3751 6 days ago cmd /S /C powershell -Command Sleep 2 ; Inv 127.2 MB
d43abb81204a 7 days ago cmd /S /C powershell -Command Sleep 2 ; Inv 66.46 MB
7a21073861a1 7 days ago cmd /S /C powershell -Command Sleep 2 ; Inv 115.8 MB
6801d964fda5 5 months ago
使用影像快取時,如何排序指示很重要,如下一節所示。
訂購指示
Dockerfile 是從上到下進行處理,每個指令會和快取層進行比較。 當指令沒有快取層時,此指令和所有後續的指令會在新容器映像層中進行處理。 有鑑於此,指令的放置順序非常重要。 在 Dockerfile 上層放置會保持固定的指令。 在 Dockerfile 下層放置可能會有所改變的指令。 這樣做可以降低取消現有快取的可能性。
下列範例示範 Dockerfile 指令順序如何影響快取效率。 這個簡單的範例 Dockerfile 有四個編號的資料夾。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN mkdir test-1
RUN mkdir test-2
RUN mkdir test-3
RUN mkdir test-4
產生的映射有五層,一個用於基底 OS 映射和每個 RUN
指示。
docker history doc-sample-1
IMAGE CREATED CREATED BY SIZE COMMENT
afba1a3def0a 38 seconds ago cmd /S /C mkdir test-4 42.46 MB
86f1fe772d5c 49 seconds ago cmd /S /C mkdir test-3 42.35 MB
68fda53ce682 About a minute ago cmd /S /C mkdir test-2 6.745 MB
5e5aa8ba1bc2 About a minute ago cmd /S /C mkdir test-1 7.12 MB
6801d964fda5 5 months ago 0 B
這個下一個 Dockerfile 現在已稍微修改,第三 RUN
個指令已變更為新的檔案。 當 Docker 建置針對此 Dockerfile 執行時,前三項指令 (和上個範例中的指令完全相同) 會使用快取映像層。 不過,因為不會快取變更的指令,所以會針對已變更 RUN
的指令和所有後續指示建立新的圖層。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN mkdir test-1
RUN mkdir test-2
RUN mkdir test-5
RUN mkdir test-4
當您比較新影像的影像識別碼與本節第一個範例中的影像識別碼時,您會發現前三層從下到上都是共用的,但第四層和第五層是唯一的。
docker history doc-sample-2
IMAGE CREATED CREATED BY SIZE COMMENT
c92cc95632fb 28 seconds ago cmd /S /C mkdir test-4 5.644 MB
2f05e6f5c523 37 seconds ago cmd /S /C mkdir test-5 5.01 MB
68fda53ce682 3 minutes ago cmd /S /C mkdir test-2 6.745 MB
5e5aa8ba1bc2 4 minutes ago cmd /S /C mkdir test-1 7.12 MB
6801d964fda5 5 months ago 0 B
外觀優化
指令案例
Dockerfile 指令不區分大小寫,但慣例是使用大寫。 這可藉由區分指令呼叫和指令作業來改善可讀性。 下列兩個範例會比較未資本化和大寫的 Dockerfile。
以下是未使用Capitalized Dockerfile:
# Sample Dockerfile
from mcr.microsoft.com/windows/servercore:ltsc2019
run dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
run echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
cmd [ "cmd" ]
以下是使用大寫的相同 Dockerfile:
# Sample Dockerfile
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN dism /online /enable-feature /all /featurename:iis-webserver /NoRestart
RUN echo "Hello World - Dockerfile" > c:\inetpub\wwwroot\index.html
CMD [ "cmd" ]
換行
長和複雜的作業可以透過反斜線 \
字元分隔成多行。 下列 Dockerfile 會安裝 Visual Studio 可轉散發套件、移除安裝程式檔案,然後建立設定檔。 這三項作業都是在單行中指定。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell -Command c:\vcredist_x86.exe /quiet ; Remove-Item c:\vcredist_x86.exe -Force ; New-Item c:\config.ini
命令可以使用反斜線來細分,以便從一個 RUN
指令的每個作業都在其自己的行上指定。
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
Start-Process c:\vcredist_x86.exe -ArgumentList '/quiet' -Wait ; \
Remove-Item c:\vcredist_x86.exe -Force ; \
New-Item c:\config.ini