Docker系列之鏡像瘦身(五)

前言

本節咱們來說講在咱們在構建鏡像過程當中不出問題,同時使得最後所構建的鏡像文件大小盡量最小,舒適提示:文中大圖都可點擊放大查看詳細信息。linux

緩存(cache)

Docker的優點之一在於提供了緩存,加速鏡像迭代構建,咱們知道構建鏡像使用docker build命令,也就是說經過docker build的緩存機制實現了鏡像的複用,不只節省鏡像存儲空間,也爲鏡像構建節省了大量時間。git

 

Docker會由上至下逐步執行Dockerfile中的指令,按順序執行每一個指令,在檢查每條指令時,Docker在其緩存中查找現有的中間圖像,可能會重用而不是建立新的中間圖像,若是緩存無效,則使其無效的指令和後續全部Dockerfile指令都會從新生成新的中間鏡像。一旦緩存失效,就可使用Dockerfile中的其他指令,因此從Dockerfile的頂部開始,若是基礎映像(父鏡像)已經在緩存中,則重用。而後繼續執行下一條指令與從該基礎圖像導出的高速緩存中全部子鏡像進較,比較每一個緩存的中間鏡像以查看指令是否找到並緩存是否命中,若是高速緩存未命中,則高速緩存無效,如此重複執行以上過程,最終到達Dockerfile的末尾。大多數新指令只是與中間鏡像中的指令進行比較,若是匹配,則使用緩存副本。好比,當在Dockerfile中執行RUN pip install -r test.txt指令時,Docker會在其本地緩存的中間圖像中搜索相同的指令,可是舊的和新的test.txt文件中的內容不會進行比較。若是咱們使用新軟件包更新test.txt文件並使用RUN pip install指令但願使用新軟件包名稱從新運行軟件包安裝,若是是這種狀況可能會出現問題。同時呢,ADD和COPY與其餘Docker指令不一樣,ADD和COPY指令須要Docker查看文件中的內容以肯定是否存在緩存命中,Docker將會引用文件內容的校驗和與現有中間圖像中的校驗和進行比較,若是文件內容或元數據已更改,則緩存無效。github

 

從如上咱們對Dokcer緩存機制的大體講解,若咱們對指令進行了更改,那麼該指令的後續每一層可能會常常重建,因此爲了更好的利用緩存,咱們須要將可能須要更改的指令儘量的放在比較低的位置。當咱們在構建鏡像時咱們能夠指定參數(--no-cache=true)來關閉緩存。當咱們須要更新源時,咱們經過鏈式調用apt-get-update和apt-get-install來避免緩存丟失問題。web

 

在Docker中咱們能夠經過命令來監控文件鏡像和容器文件大小,咱們知道 docker container ls 命令查看容器列表, docker container ls -s 則能夠查看容器大小,以下:docker

爲了查看鏡像構建中中間鏡像歷史記錄,使用命令 docker image history imagename:tag ,爲了更清晰看到鏡像中每一層的內容,咱們可使用庫https://github.com/wagoodman/dive,好比咱們上一節所構建的鏡像爲webapi。咱們安裝完dive庫後,而後查看鏡像中的每一層,經過以下命令。api

docker run --rm -it \
           -v /var/run/docker.sock:/var/run/docker.sock \
           quay.io/wagoodman/dive:latest \
           webapi:latest

點擊放大

文件忽略(.dockerignore)

咱們知道Docker有兩個組件:客戶端和守護進程,當咱們編寫docker命令時,咱們使用客戶端向Docker deamon發送命令,該命令執行全部工做,這裏咱們須要知道客戶端和守護進程能夠單獨部署到兩臺獨立機器上,爲了讓Docker守護進程使用docker build從Dockerfile文件中構建映像,客戶端須要向其發送執行命令的「上下文」, 上下文基本上能夠說是傳遞給docker build命令的目錄中的全部文件,使用Dockerfile構建時,咱們在客戶端能夠清楚看到發送的上下文,例如以下:緩存

對於大型項目而言,上下文可能會變得很是大,毫無疑問這將會減緩經過Dockerfile構建鏡像的速度,由於咱們必須等待客戶端將全部文件發送到守護進程。好比在ASP.NET Core應用程序中,在項目根目錄下可能包含大量文件,這些文件對於大多數Dockerfile構建來講都不是必需的,好比Git文件或者SVN文件,obj、bin等文件, 全部這些附加文件在做爲上下文的一部分發送時會減慢構建速度。docker爲咱們提供瞭解決方案,咱們能夠經過在根目錄中建立.dockerignore文件來忽略不須要的文件,.dockerignore相似於.gitignore文件,其中包含Docker與文件名匹配的模式列表,並在製做鏡像時忽略,好比以下忽略網絡

當咱們在客戶端執行docker build命令來建立映像時,Docker會檢查.dockerignore文件,若是存在此文件,它會逐行瀏覽文件並使用Go的filepath.Match規則以及Docker自身的一些規則來匹配文件名以此來進行忽略。好比在.dockerignore文件中包含* .vs將排除帶有.vs擴展名的文件。咱們可使用以#開頭的註釋來解釋在.dockerignore中正在執行的操做。 .dockerignore能夠幫助減少鏡像大小,文件越少意味着鏡像越小,鏡像越快,減小構建緩存失效,若是日誌或其餘文件正在更改,而且咱們的鏡像因其緩存而使其緩存失效,則會下降構建週期。綜上咱們針對須要使得咱們所構建的鏡像能夠注意如下幾方面:app

1.使用官方鏡像,可能不少文章或博客講解的鏡像已過期。工具

2.若可能,儘量使用Alpine鏡像,以保持鏡像輕量級。

3.若是使用apt,在同一指令中將RUN apt-get update與apt-get install結合使用, 而後在該鏈式指令中連接多個包, 使用\字符在多行中按字母順序列出包,最後使用rm -rf /var/lib/apt/lists/* 的目的在於清除apt緩存而不會使其緩存保存到鏡像層上。 例如:RUN apt-get update && apt-get install -y \package-one \package-two && rm -rf /var/lib/apt/lists/*

4.將可能須要更改的指令儘可能放在Dockerfile比較低的位置(可能的話)

5..使用.dockerignore文件將不須要的和沒必要要的文件留在鏡像以外。

6.能夠嘗試結合使用dive庫監控鏡像層,而後合理優化鏡像大小。

.NET Core使用Docker優化鏡像大小 

接下來咱們來一塊兒看看針對上一節所寫的Dockerfile文件進行分析,看看是否能夠爲鏡像瘦身而進一步優化,上一節的構建鏡像文件說明書以下:

首先咱們獲取基礎鏡像,而後只是複製項目文件而不是複製全部文件,這能夠避免額外無關的還原,並容許咱們重用中間鏡像層,若是咱們更改項目文件,只是會再次來一遍從新複製,這也就意味着更快的構建!若是是自包含的應用程序,咱們下載對應的鏡像而不包含運行時鏡像,這樣鏡像大小最小,同時最後運行時自包含應用程序則無需使用dotnet命令,直接切換到項目根目錄經過CMD執行便可。

咱們使用預發佈的包工具《https://www.nuget.org/packages/Microsoft.Packaging.Tools.Trimming/1.1.0-preview1-25818-01》,經過它咱們能夠查看應用程序並刪除沒有調用的代碼和二進制文件,接下來咱們包括Microsoft.Packaging.Tools.Trimming添加包以及忽略文件基於上一節構建鏡像進行以下改造。
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build

WORKDIR /app

COPY *.csproj ./
RUN dotnet restore

COPY . ./

RUN dotnet add package Microsoft.Packaging.Tools.Trimming -v 1.1.0-preview1-25818-01

RUN dotnet publish -c Release -o out -r linux-arm /p:LinkDuringPublish=true

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS runtime
WORKDIR /app

COPY --from=build /app/out .

ENV ASPNETCORE_URLS=http://+:8080

ENTRYPOINT ["dotnet", "WebApi.dll"]

由如上第一張圖咱們能夠看到,當咱們添加了忽略文件後,它將上下文從4.206MB減小到16.9KB,而無需花費更多時間來發送上下文,如今能夠說是秒送。 

總結 

本節咱們詳細講解了從哪幾方面入手來瘦身鏡像,下一節咱們深刻講講Docker中的網絡內容,感謝您的閱讀,下節再會。 

相關文章
相關標籤/搜索