Windows Containers 大冒險: 優化計劃(Dockerfile)

前言

有必定旅行經驗的朋友都知道,即便在出發前制定了詳細的出行計劃,也會在路途中由於各式各樣的情況而不得不從新修改計劃。這個情況在咱們編寫Dockerfile時同樣存在。花了30分鐘編寫的Dockerfile在構建鏡像的時候也會出現各式各樣的情況。那麼編寫Dockerfile時有哪些能夠優化的點呢?docker

在瞭解可優化點以前,先來了解下容器的分層文件系統。shell

分層文件系統

分層文件系統是容器技術中的重要概念,當經過Dockerfile構建鏡像時,每個可執行指令會被容器引擎一一執行,並造成臨時的容器。最終疊加在一塊兒成爲新的鏡像。這裏有個名詞,叫可執行指令,最經常使用的就是RUN指令,由於RUN指令會在構建時會造成新的鏡像層。其它建立文件層的指令還有ADD和COPY。windows

對於如下的Dockerfile,能夠經過 docker history 來查看分層文件系統的結構。各位須要注意的是docker history的輸出結果和Dockerfile中指令的前後順序。緩存

#escape=`

FROM microsoft/windowsservercore:1803

SHELL [ "powershell", "-command" ]

RUN $ErrorActionPreference = 'Stop'; `
    $ProgressPreference = 'SilentlyContinue'; `
    $null = New-Item -Path c:\apps -Type Directory

RUN Invoke-WebRequest -Uri https://download.sysinternals.com/files/SysinternalsSuite.zip `
                      -UseBasicParsing -OutFile c:\apps\SysinternalsSuite.zip `
                      -Proxy http://192.168.0.124:1080; `
    Expand-Archive -Path C:\apps\SysinternalsSuite.zip -DestinationPath C:\apps\sysinternals\ -Force; `
    Remove-Item -Path c:\apps\SysinternalsSuite.zip

ENTRYPOINT [ "powershell" ]
$ docker history greggu/sysinternals:20170516
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
64b20b828374        2 weeks ago         powershell -command #(nop)  ENTRYPOINT ["pow…   41kB
5b6b75a8ed6c        2 weeks ago         powershell -command Invoke-WebRequest -Uri h…   94.2MB
8cdde7fb6229        2 weeks ago         powershell -command $ErrorActionPreference =…   39MB
214857b207fb        2 weeks ago         powershell -command #(nop)  SHELL [powershel…   41kB
ad6116672030        6 weeks ago         Install update 10.0.14393.2189                  2.79GB
<missing>           17 months ago       Apply image 10.0.14393.0                        7.68GB

優化Dockerfile

對相關指令採起分組合並

首先針對如下Dockerfile構建鏡像,請在構建過程當中觀察輸出,也可使用docker history查看。網絡

FROM microsoft/windowsservercore:1803

SHELL [ "powershell", "-command" ]

RUN $ErrorActionPreference = 'Stop'
RUN $ProgressPreference = 'SilentlyContinue'
RUN $null = New-Item -Path c:\apps -Type Directory
$ docker history greggu/test:0.0.1
IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
158b934a3b80        About a minute ago   powershell -command $null = New-Item -Path c…   32.7MB
e3b45ff79cc9        2 minutes ago        powershell -command $ProgressPreference = 'S…   32.7MB
a61529eb0225        2 minutes ago        powershell -command $ErrorActionPreference =…   39.1MB
214857b207fb        2 weeks ago          powershell -command #(nop)  SHELL [powershel…   41kB
ad6116672030        6 weeks ago          Install update 10.0.14393.2189                  2.79GB
<missing>           17 months ago        Apply image 10.0.14393.0                        7.68GB

能夠看到每一句RUN指令都新生成了一層鏡像層,致使鏡像大小變大。優化的方法就是使用;和`(換行符)將多條PowerShell語句合併成一條執行。也就是在本文最開始使用的例子。app

移除再也不須要的文件

仍是本文最開始使用的例子,在這個例子中,首先從網絡下載SysinternalsSuite.zip壓縮包,隨後執行了解壓操做。最後執行Remove-Item操做把壓縮包刪除。而這個刪除操做減少了鏡像體積。這點你們很容易理解,再也不須要的文件刪除便可。固然這裏還有一個小點,爲了讓Dockerfile能在任意位置被使用,通常推薦經過網絡下載所依賴的文件。因此Invoke-WebRequest的經常使用參數也是須要掌握的。優化

合理使用分層文件系統

在以前的例子中,各位能夠看到每一行RUN指令都生成了新的一層鏡像,從而增長最終鏡像的大小。那麼是否是意味這把全部指令都寫在一行內就完成了最佳優化實踐呢?這個理解是不對的。爲了在構建鏡像時使用到Docker的緩存功能,須要對構建指令進行分組。請各位準備如下兩個Dockerfile並執行構建操做,並特別留意構建第二個鏡像時第3步的輸出。ui

# escape=`

FROM microsoft/windowsservercore:1803

SHELL [ "powershell", "-command" ]

RUN $ErrorActionPreference = 'Stop'; `
    $ProgressPreference = 'SilentlyContinue'; `
    $null = New-Item -Path c:\demos -Type Directory

RUN $null = New-Item -Path c:\demos\demo01 -Type Directory
# escape=`

FROM microsoft/windowsservercore:1803

SHELL [ "powershell", "-command" ]

RUN $ErrorActionPreference = 'Stop'; `
    $ProgressPreference = 'SilentlyContinue'; `
    $null = New-Item -Path c:\demos -Type Directory

RUN $null = New-Item -Path c:\demos\demo02 -Type Directory

由於使用了兩個Dockerfile,須要在docker build時指定具體的Dockerfile,具體構建命令能夠放在一個批處理文件中日誌

docker build -f Dockerfile.1 --rm --tag greggu/demo01:0.0.1 .
docker build -f Dockerfile.2 --rm --tag greggu/demo02:0.0.1 .

構建日誌code

PS C:\Users\greggu\repos\dow-playground\windows\demo02> .\build.ps1
Sending build context to Docker daemon  4.096kB
Step 1/4 : FROM microsoft/windowsservercore:1803
 ---> 7e2287b03e2e
Step 2/4 : SHELL [ "powershell", "-command" ]
 ---> Running in cb5a6e633a04
Removing intermediate container cb5a6e633a04
 ---> 8fc2f8b81b5b
Step 3/4 : RUN $ErrorActionPreference = 'Stop';     $ProgressPreference = 'SilentlyContinue';     $null = New-Item -Path c:\demos -Type Directory
 ---> Running in dce5d9150f26
Removing intermediate container dce5d9150f26
 ---> 922a8037b585
Step 4/4 : RUN $null = New-Item -Path c:\demos\demo01 -Type Directory
 ---> Running in 69d0d0277786
Removing intermediate container 69d0d0277786
 ---> 57bde82f4a6f
Successfully built 57bde82f4a6f
Successfully tagged greggu/demo01:0.0.1
Sending build context to Docker daemon  4.096kB
Step 1/4 : FROM microsoft/windowsservercore:1803
 ---> 7e2287b03e2e
Step 2/4 : SHELL [ "powershell", "-command" ]
 ---> Using cache
 ---> 8fc2f8b81b5b
Step 3/4 : RUN $ErrorActionPreference = 'Stop';     $ProgressPreference = 'SilentlyContinue';     $null = New-Item -Path c:\demos -Type Directory
 ---> Using cache
 ---> 922a8037b585
Step 4/4 : RUN $null = New-Item -Path c:\demos\demo02 -Type Directory
 ---> Running in 295a54558ab5
Removing intermediate container 295a54558ab5
 ---> 386e4f6cd28d
Successfully built 386e4f6cd28d
Successfully tagged greggu/demo02:0.0.1

對指令進行排序

因爲Docker在處理Dockerfile時是自頂向下處理的,每行指令將和緩存的文件層進行對比。若是緩存中沒有所需的文件層,Docker將按照Dockerfile的指令進行構建。爲了合理利用緩存從而加快鏡像構建速度,通常推薦將在多個鏡像中共享的文件層的構建指令放在Dockerfile前部,而改變的部分放在Dockerfile尾部,具體的Dockerfile能夠參考上一個優化建議。

Dockerfile編寫風格

在編寫Dockerfile時,通常遵循如下兩點。第一點,全部Docker指令在Dockerfile中須要大寫,從而和具體的操做命令區分開來。第二點,對於過長的指令請合理使用換行符,從而增長Dockerfile的可閱讀性。

總結

本文總結了在構建Windows容器時,如何對Dockerfile進行優化,提升構建效率,在各位編寫多個Dockerfile以後,相信會增長對本文的理解。

相關文章
相關標籤/搜索