.NET Core 的 Dockerfile 中的阶段顺序

Order of stages in Dockerfile for .NET Core

作为 Docker 的新手,我目前正在阅读一些教程,但有两件事我不太明白。根据官方 Docker documentation,Docker 文件可能如下所示:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY ../engine/examples ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

第一阶段导入sdk,第二阶段导入dotnet 运行time。但是,在其他教程中,例如this one from Jetbrains,顺序颠倒;首先导入 运行time,然后导入 sdk。

第一个问题;是否有优先的进口顺序(为什么)?

第二个问题,在上面的例子中,首先复制csproj,dotnet restore是运行,然后在构建应用程序之前复制所有其他文件。为什么不一次复制所有内容?

它们的结构方式与最大限度地使用以前构建的缓存层以使构建速度更快以及使用比完整 SDK 图像更小的运行时基图像有很大关系.

如果你不关心构建速度和图像大小,你可以做一些非常简单的事情,比如

FROM mcr.microsoft.com/dotnet/sdk:6.0
WORKDIR /src
COPY . .
RUN dotnet publish -o out
WORKDIR /src/out
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

这个 Docker 文件将必须在您每次更改文件时构建所有内容。您可以通过意识到很少更改 .csproj 文件来加快 Nuget 包的恢复。

FROM mcr.microsoft.com/dotnet/sdk:6.0
WORKDIR /src
COPY aspnetapp.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -o out
WORKDIR /src/out
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

现在,当您只更改一些代码(但不更改 .csproj 文件)时,Docker 会看到直到 COPY . . 一切都与您上次 运行 时相同 docker build,所以它只会从缓存中取出图层,您实际上 运行 dotnet restore 可以节省一些时间。

为了在最终图像上保留一些 space,我们可以使用 aspnet 图像作为基础,而不是 sdk 图像。为此,我们可以使用 multistage Dockerfile 并将文件从第一阶段复制到最后(和最终)阶段,如下所示

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY aspnetapp.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -o out

FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /src/out /app
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

现在最终的图像更小了,所以我们 运行 它占用的资源更少。