Docker 中的 .NET 包恢复与构建分开缓存

Pal*_*lec 3 docker nuget-package-restore .net-core

如何构建 .NET 5/C# 应用程序的 Docker 映像,以便正确缓存恢复的 NuGet 包?通过正确的缓存,我的意思是当源(而不是项目文件)发生更改时,包含恢复的包的图层仍然会在docker build.

Docker 中的最佳实践是在添加完整源并构建应用程序本身之前执行包恢复,因为这样可以单独缓存恢复,从而显着加快构建速度。我知道不仅要保留packages目录,还要保留各个项目的bin和目录,以便一切都能协同工作。我还知道,一旦缓存被破坏,所有后续层都会重新构建。objdotnet restoredotnet publish --no-restore

我的问题是我无法想出一种方法来仅复制*.csproj. 如果我复制的不仅仅是*.csproj,源更改会破坏缓存。我可以将它们复制到外部的一个地方docker build,然后简单地将它们复制到构建内部,但我希望能够使用相当简单的命令手动构建图像,甚至在管道外部。(这个要求是否不合理?)

对于由相当标准的文件夹结构中的多个项目组成的 Web 应用程序src/*/*.csproj,我提出了这种尝试,试图补偿复制到图像中的太多文件(这仍然会破坏缓存):

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /src
COPY NuGet.Config NuGet.Config
COPY src/ src/
RUN find . -name NuGet.Config -prune -o \! -type d \! -name \*.csproj -exec rm -f '{}' + \
    && find -depth -type d -empty -exec rmdir '{}' \;
RUN dotnet restore src/Company.Product.Component.App/Company.Product.Component.App.csproj
COPY src/ src/
RUN dotnet publish src/Company.Product.Component.App/Company.Product.Component.App.csproj -c Release --no-restore -o /out

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS run-env
WORKDIR /app
COPY --from=build-env /out .
ENTRYPOINT ["dotnet", "Company.Product.Component.App.dll"]
Run Code Online (Sandbox Code Playgroud)

我还尝试在恢复后将 build-env 阶段分成两个,将 /root/.nuget/packages 和 /src 复制到构建阶段,但这也没有帮助。

第一个 RUN 行和之前的行应该替换为仅复制 的内容*.csproj,但我不知道那是什么。明显费力的解决方案是为每个文件设置一个单独的 COPY 行*.csproj,但这感觉不太对劲,因为项目往往会被添加和删除,因此这使得 Dockerfile 难以维护。我尝试过COPY src/*/*.csproj src/然后修复扁平路径,这是我在 google 上搜索的一个技巧,但它对我不起作用,因为我的 Docker 仅处理文件名中的通配符并按字面解释目录名,从而发出不存在src/*目录的错误。我正在使用Docker Desktop 3.5.2 (66501),它使用 BuildKit 后端来构建映像,但如果有帮助的话,我愿意更改工具。

这让我不知道如何满足我相对简单的一组要求。我的选择似乎已经用尽了。我错过了什么吗?我是否必须接受折衷并放弃一些要求?

Pal*_*lec 8

目录名称中缺乏对通配符的支持可能是BuildKit 中缺少的功能。该问题已在moby/buildkit GitHub 上报告为 #1900

在问题解决之前,如果您不需要BuildKit 的任何功能,请禁用它。任何一个

  1. 将环境变量 DOCKER_BUILDKIT 设置为零 ( 0),或者
  2. 编辑 Docker 守护进程配置,将“buildkit”功能设置为 false 并重新启动守护进程。

在 Docker Desktop 中,可以在“设置”>“Docker 引擎”中轻松访问该配置。Docker Desktop 3.2.0 发行说明中推荐了这种关闭该功能的方法,其中 BuildKit 首次默认启用。

一旦 BuildKit 被禁用,替换

COPY src/ src/
RUN find . -name NuGet.Config -prune -o \! -type d \! -name \*.csproj -exec rm -f '{}' + \
    && find -depth -type d -empty -exec rmdir '{}' \;
Run Code Online (Sandbox Code Playgroud)

COPY src/*/*.csproj src/
RUN for from in src/*.csproj; do to=$(echo "$from" | sed 's/\/\([^/]*\)\.csproj$/\/\1&/') \
    && mkdir -p "$(dirname "$to")" && mv "$from" "$to"; done
Run Code Online (Sandbox Code Playgroud)

COPY 将成功,而不会破坏缓存,并且 RUN 将修复路径。它依赖于项目位于“src”目录中的事实,每个项目都位于与项目文件同名的单独目录中。

这基本上是VonC 对相关问题的回答底部的解决方案。答案还提到了Moby 问题#15858,其中有关于该主题的有趣讨论。

也有一个用于路径修复的 dotnet 工具,但我还没有测试过它。

不需要禁用 BuildKit 的替代解决方案是在清理复制的文件后立即将原始阶段分成两部分,即在恢复之前(而不是之后!)。

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS projects-env
WORKDIR /src
COPY NuGet.Config NuGet.Config
COPY src/ src/
RUN find . -name NuGet.Config -prune -o \! -type d \! -name \*.csproj -exec rm -f '{}' + \
    && find . -depth -type d -empty -exec rmdir '{}' \;

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /src
COPY --from=projects-env /src /src
RUN dotnet restore src/Company.Product.Component.App/Company.Product.Component.App.csproj
COPY src/ src/
RUN dotnet publish src/Company.Product.Component.App/Company.Product.Component.App.csproj -c Release --no-restore -o /out

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS run-env
WORKDIR /app
COPY --from=build-env /out .
ENTRYPOINT ["dotnet", "Company.Product.Component.App.dll"]
Run Code Online (Sandbox Code Playgroud)

COPY src/ src/源环境中的层会因源代码更改而失效,但缓存失效会针对每个阶段单独工作。由于复制到 build-env 的文件在各个构建中都是相同的,因此COPY --from=projects-env缓存不会失效,因此该RUN dotnet restore层也会从缓存中获取。

我怀疑还有其他使用BuildKit 安装座的解决方案(RUN --mount=...),但我还没有测试过。


小智 5

这是解决问题的替代方法。

首先,复制.sln.csproj文件(取决于解决方案文件夹结构)

COPY *.sln ./
COPY **/*.csproj ./
COPY **/**/**/*.csproj ./
Run Code Online (Sandbox Code Playgroud)

之后运行以下脚本:

RUN dotnet sln list | grep ".csproj" \
    | while read -r line; do \ 
    mkdir -p $(dirname $line); \
    mv $(basename $line) $(dirname $line); \
    done;
Run Code Online (Sandbox Code Playgroud)

该脚本只是将.csproj文件移动到它们在主机文件系统中的相同位置。


归档时间:

查看次数:

4675 次

最近记录:

2 年,6 月 前