在編寫Dockerfile構建docker鏡像時,常遇到以下問題: 為瞭解決上述問題,從17.05版本開始Docker在構建鏡像時增加了新特性:多階段構建(multi-stage builds),將構建過程分為多個階段,每個階段都可以指定一個基礎鏡像,這樣在一個Dockerfile就能將多個鏡像的特 ...
在編寫Dockerfile構建docker鏡像時,常遇到以下問題:
- RUN命令會讓鏡像新增layer,導致鏡像變大,雖然通過&&連接多個命令能緩解此問題,但如果命令之間用到docker指令例如COPY、WORKDIR等,依然會導致多個layer;
- 有些工具在構建過程中會用到,但是最終的鏡像是不需要的(例如用maven編譯構建java工程),這要求Dockerfile的編寫者花更多精力來清理這些工具,清理的過程又可能導致新的layer;
為瞭解決上述問題,從17.05版本開始Docker在構建鏡像時增加了新特性:多階段構建(multi-stage builds),將構建過程分為多個階段,每個階段都可以指定一個基礎鏡像,這樣在一個Dockerfile就能將多個鏡像的特性同時用到,例如:先用SDK鏡像構建.NET Core工程,再把構建結果和Runtime 合成,就做成了一個可以直接運行.NET Core工程鏡像了;
官方描述如下圖所示,地址是:https://docs.docker.com/develop/develop-images/multistage-build/
官方的實例是golang的,今天我們以.NET Core構建ASP.NET Core工程為例,介紹如何使用multi-stage特性構建.NET Core微服務鏡像;
Dockerfile文件參見: https://github.com/geffzhang/AKS-learning-series/blob/master/src/TechTalksWeb/Dockerfile
### 第一階段,用sdk 鏡像進行編譯
FROM microsoft/dotnet:2.1.300-sdk AS build-env
WORKDIR /TechTalksWeb
COPY NuGet.config ./
COPY TechTalksWeb.csproj ./
RUN dotnet restore
COPY . ./
#編譯構建
RUN dotnet publish --configuration Release --output releaseOutput --no-restore
#build runtime image
### 第二階段,用第一階段的.NET Core編譯文件和aspnetcore-runtime 鏡像合成一個小體積的鏡像
FROM microsoft/dotnet:2.1.0-aspnetcore-runtime
WORKDIR /TechTalksWeb
#從名為build-env的stage複製構建結果到工作目錄
COPY --from=build-env /TechTalksWeb/releaseOutput ./
ENTRYPOINT ["dotnet", "TechTalksWeb.dll"]
上面就是分成了兩個階段構建的Dockerfile腳本,請參考每行的註釋來理解,有以下幾點需要重點關註:
- 一共有兩次FROM指令出現,而最終的鏡像是基於最後一個FROM生成的;
- WORKDIR 被定義了兩次,因為前面階段定義的變數在後面的階段是用不了的;
- COPY --from=build-env 這個命令,可以將指定階段的文件複製到當前階段來,這一步很關鍵,第一階段用.NET Core SDK構建出來的dll 文件,通過該命令複製到後面的階段來使用了;
- 最後一個FROM是microsoft/dotnet:2.1.0-aspnetcore-runtime,這是asp.net core 運行環境鏡像,最終鏡像的內容就是dotnet:2.1.0-aspnetcore-runtime和sdk的構建結果,而前面的sdk鏡像和最終構建結果無關;