基礎準則
- 儘量挑選官方鏡像
- 選擇合適的基礎鏡像
- 能用小的就不要用大的
- 能用輕量級的就不要用重量級的
- 儘量選擇用runtime的
- 利用多階段構建
- 優化指令順序: 變動越小的放在越前面
選擇合適的基礎映像
選擇正確的基礎映像是優化的第一步。對於ASP.NET Core應用,推薦使用官方的ASP.NET Core運行時映像。這些映像已經為性能和安全性進行了優化,且體積相對較小。
下面以asp.net core 6.0
的Web專案建立Dockerfile並分析其內容:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
多階段構建
多階段構建可以幫助您在一個Dockerfile中分別進行應用的構建和運行,這樣可以大大減少最終映像的大小。
# 構建階段
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"
COPY . .
WORKDIR "/src/MyApp"
RUN dotnet build "MyApp.csproj" -c Release -o /app/build
# 發布階段
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
# 運行階段
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
構建Image過程分析
使用Dockerfile建立Image過程中,每個可執行的指令基本上都會產生一個新的層(快照)。在上面的Dockerfile 中,指令及其對應的層如下:
在 Docker 中,每個可執行的指令基本上都會產生一個新的層(快照)。在您問的 Dockerfile 範例中,指令及其對應的層如下:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
- 第一個基礎映像層WORKDIR /app
- 變更工作目錄到/appEXPOSE 80
- 暴露PortEXPOSE 443
- 暴露PortFROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
- 第二個基礎映像層(用於建置)WORKDIR /src
- 變更工作目錄COPY ["MyApp/MyApp.csproj", "MyApp/"]
- 複製專案檔案到image的/src的MyApp目錄下(不存在則建立)RUN dotnet restore "MyApp/MyApp.csproj"
- Restore專案及相關套件COPY . .
- 複製本地目錄所有檔案到到image的/src中WORKDIR "/src/MyApp"
- 再次變更工作目錄RUN dotnet build "MyApp.csproj" -c Release -o /app/build
- 建置應用程序FROM build AS publish
- 從建置階段開始新的階段RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
- 發布應用程序FROM base AS final
- 從基礎映像開始最終階段WORKDIR /app
- 變更工作目錄到/app(可能不會產生新層,因為這個工作目錄已經在基礎映像階段被設定)COPY --from=publish /app/publish .
- 從發布階段複製檔案到/appENTRYPOINT ["dotnet", "MyApp.dll"]
- 設置容器入口點
案例-變更Promgram.cs重新建𦋠Image的緩存使用
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
- 使用快取,因為基礎映像沒有改變。WORKDIR /app
- 使用快取,這一步和Program.cs
的改變無關。EXPOSE 80
- 使用快取,無相關改變。EXPOSE 443
- 使用快取,無相關改變。FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
- 使用快取,同樣因為基礎映像沒有改變。WORKDIR /src
- 使用快取,這一步和Program.cs
的改變無關。COPY ["MyApp/MyApp.csproj", "MyApp/"]
- 使用快取,假設.csproj
檔案沒有改變。RUN dotnet restore "MyApp/YourApp.csproj"
- 使用快取,因為沒有.csproj
檔案的改變。COPY . .
- 重新建置新層,因為您修改了Program.cs
,而這一步涉及複製整個專案目錄。WORKDIR "/src/MyApp"
- 重新建置新層,因為它跟在一個已經改變的層後面。RUN dotnet build "MyApp.csproj" -c Release -o /app/build
- 重新建置新層,需要重新編譯因為源代碼已經改變。FROM build AS publish
- 重新建置新層,這是一個新階段,而前面的步驟已經更改。RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
- 重新建置新層,必須發布修改後的代碼。FROM base AS final
- 使用快取,回到了最初的基礎映像,且此時階段與Program.cs
的修改無關。WORKDIR /app
- 使用快取,如果這個指令沒有在前面的基礎映像層中被改變。COPY --from=publish /app/publish .
- 重新建置新層,需要從已更新的發布階段複製文件。ENTRYPOINT ["dotnet", "MyApp.dll"]
- 重新建置新層,雖然這個指令本身未改變,但它跟隨在已更改的層後面。
總之,合理規劃 Dockerfile 中命令的順序對於優化建置過程、減少建置時間、利用 Docker 快取、降低映像大小,以及保持容易維護性都非常重要。
沒有留言:
張貼留言