1. 程式人生 > >Docker鏡像優化

Docker鏡像優化

version fin lds fir 並且 以及 替代 href 介紹

原文:Docker鏡像優化

前言

上篇博文說到使用Visual Studio Tools for Docker幫助我們生成Dockerfile,現在我們討論下生成的Dockerfile的優劣。


一、以往Dockerfile構建模式

(1)發布API項目

新建Web API項目,項目名稱為API

在項目所在目錄輸入指令:dotnet publish --runtime ubuntu.16.04-x64

(2)創建鏡像

在發布目錄新建Dockerfile文件,黏貼以下代碼

# 聲明使用的基礎鏡像

FROM microsoft/dotnet:2.1-sdk # 設置工作目錄 WORKDIR /app # 將本地應用拷貝到 容器/app 目錄下 COPY ./ ./ # 設置導出端口 EXPOSE 80 # 指定應用入口點 API.dll代表的是主程序文件 ENTRYPOINT ["dotnet", "API.dll"]

在Dockerfile所在的目錄下輸入指令生成鏡像:docker build -t api .

不要忘記後面有一個點 .

技術分享圖片

生成api:latest鏡像成功

參考博客操作步驟:https://www.cnblogs.com/bluesummer/p/8087326.html

(3)分析鏡像

我們來查看鏡像信息,輸入:docker images

技術分享圖片

發現api:latest鏡像的大小為1.83GB,大得有點誇張。

現在我們來分析這個Dockerfile:

FROM microsoft/dotnet:2.1-sdk

FROM:指定所創建的基礎鏡像,如果本地不存在,則默認去Docker Hub下載指定鏡像。任何Dockerfile中的第一條指令必須為FROM指令。並且,如果在同一個Dockerfile中創建多個鏡像,可以使用多個FROM指令。

文中Dockerfile基於microsoft/dotnet:2.1-sdk

鏡像,而圖中可看到,microsoft/dotnet:2.1-sdk鏡像大小已經達到1.73GB了,所以最後生成的api:latest鏡像大小為1.83GB也不足為怪。

那問題來了,我們應該采用哪個鏡像作為基礎鏡像,來創建我們自己的鏡像呢?

查閱了微軟官網文檔說明:

microsoft/dotnet:<version>-sdk包含帶有.NET Core 和命令行工具 (CLI) 的.NET Core SDK。此鏡像將映射到開發方案,可使用此鏡像進行本地開發、調試和單元測試。

microsoft/dotnet:<version>-runtime包含.NET Core(runtime和庫),並且針對在生產環境中運行.NET Core 應用進行了優化。

我們修改Dockerfile的FROM指令為

FROM microsoft/dotnet:2.1-aspnetcore-runtime

其他指令保持不變,新建一個api:1.0.0的鏡像。

技術分享圖片

可以看到,鏡像大小瞬間小了很多。但是我們還不滿足,因為原本microsoft/dotnet:2.1-aspnetcore-runtime鏡像才253MB,而我們的鏡像是353MB。

WORKDIR /app

WORKDIR:為後續RUN、CMD和ENTRYPOINT指令設置工作目錄。可以使用多個WORKDIR,後續命令如果參數是相對路徑,則會基於之前命令指定路徑。例如:

WORKDIR /app

WORKDIR publish

WORKDIR api

最終路徑為:/app/publish/api

這個指令在這裏看上去應該優化不了。

COPY ./ ./

COPY:格式為COPY <src> <dest>。復制本地主機的<src>(為Dockerfile所在的目錄的相對路徑)下的內容到容器中的<dest>下。目標路徑不存在,則自動創建。

./ ./ 就是將本地Dockerfile所在的目錄的文件和文件夾都復制到鏡像中的/app目錄下。

註意區分以下兩條指令:

COPY test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/

COPY test /absoluteDir/ # adds "test" to /absoluteDir/

想了下,這裏應該是不合理的,把全部文件都復制過去,這肯定會造成鏡像變大。

又想了下,這個已經是我們發布過的文件,那還能怎麽辦。問題先放這裏,等會再解決。

EXPOSE 80

EXPOSE:聲明鏡像內服務所監聽的端口。

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

ENTRYPOINT:指定鏡像的默認入口命令,該入口命令會在啟動容器是作為跟命令執行,所有傳入值作為該命令的參數。支持兩種格式:

ENTRYPOINT [“executable”,”param1”,”param2”] (exec調用執行)

ENTRYPOINT command param1 param2 (shell中執行)

每個Dockerfile裏若出現多個ENTRYPOINT,只有放後面的那個ENTRYPOINT有效。

Dockerfile參考:https://docs.docker.com/engine/reference/builder/#usage 裏面有各個指令的詳細介紹。


二、multi-stage builds(多階段構建)

在多階段構建的過程中,我們在Dockerfile使用多個FROM指令,每個FROM指令使用不同的基礎鏡像構成了不同階段。你可以選擇從上一個階段的產物(artifacts)復制到下一個階段,從而確保不會把不需要的東西帶到下一階段。這種方法可以有效減小Docker鏡像的大小。

默認情況下,這些階段沒有被命名,可以通過它們的整數引用它們,第一個FROM指令從0開始。然而,我們也可以以as <NAME>的方式命名每個階段。

參考官網:https://docs.docker.com/develop/develop-images/multistage-build/

以下我們用Visual Studio Tools for Docker生成的Dockerfile進行介紹。

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base

WORKDIR /app

EXPOSE 80

 

FROM microsoft/dotnet:2.1-sdk AS build

WORKDIR /src

COPY ["API/API.csproj", "API/"]

RUN dotnet restore "API/API.csproj"

COPY . .

WORKDIR "/src/API"

RUN dotnet build "API.csproj" -c Release -o /app

 

FROM build AS publish

RUN dotnet publish "API.csproj" -c Release -o /app

 

FROM base AS final

WORKDIR /app

COPY --from=publish /app .

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

它分為四個階段,分別是basebuildpublishfinal

base階段:上面已經分析了這裏不再詳述。

build階段:

FROM microsoft/dotnet:2.1-sdk AS build以microsoft/dotnet:2.1-sdk為基礎鏡像

WORKDIR /src工作目錄為/src

COPY ["API/API.csproj", "API/"]把Dockerfile所在目錄的API/API.csproj文件復制到容器的/src/API/中

RUN dotnet restore "API/API.csproj"在當前鏡像的基礎上執行dotnet restore "API/API.csproj",把API項目的依賴項和工具還原,並輸出結果。

dotnet restore這條命令是使用 NuGet 還原依賴項以及在 project 文件中指定項目特殊的工具執行對依賴項和工具的還原。

COPY . .

WORKDIR "/src/API"切換工作目錄到/src/API,可以用WORKDIR API替代,但明顯第一種方法更直觀。

RUN dotnet build "API.csproj" -c Release -o /app執行dotnet build "API.csproj" -c Release -o /app,以Release模式生成API項目及其所有依賴項並把生成的二進制文件輸出到/app目錄。

publish階段:

FROM build AS publish以上一階段build為基礎鏡像

RUN dotnet publish "API.csproj" -c Release -o /app執行dotnet publish "API.csproj" -c Release -o /app,以Release模式把API應用程序及其依賴項打包到/app目錄以部署到托管系統。

final階段:

FROM base AS final以上階段base為基礎鏡像

WORKDIR /app以/app為工作目錄

COPY --from=publish /app .把publish階段生成的/app目錄下的文件和文件夾復制到/app目錄。

這樣做的原因是,上階段的產物是不會帶到下一階段。

現在可以解釋為什麽使用Visual Studio Tools for Docker不用發布也能生成可運行的鏡像了,它實時 (JIT) 編譯,提高啟動性能。而且它只獲取了程序運行所需要的文件放到鏡像中。

我們生成一個最新的鏡像

技術分享圖片

發現它和microsoft/dotnet:2.1-aspnetcore-runtime鏡像一樣大,這下滿足了,畢竟我們沒寫什麽代碼到項目中。


三、優化Docker鏡像的方向

1.精簡鏡像用途,盡量讓每個鏡像的用途都比較集中、單一,避免構造大而復雜,功能多的鏡像。

2.選用合適的基礎鏡像。

3.在Dockerfile中寫上註釋,方便維護和他人使用。

4.正確使用版本號,如1.0.1。

5.使用多階段構建鏡像。

Docker鏡像優化