【问题标题】:Build multiple docker images without building binaries in each Dockerfile构建多个 docker 镜像,而不在每个 Dockerfile 中构建二进制文件
【发布时间】:2020-01-08 05:05:58
【问题描述】:

我有一个 .NET Core 解决方案,其中包含 6 个可运行的应用程序 (API) 和多个 netstandard 项目。在 Azure DevOps 上的构建管道中,我需要创建 6 个 Docker 映像并将它们推送到 Azure Registry。

现在我所做的是逐个映像构建,这 6 个 Dockerfile 中的每一个都从头开始构建解决方案(恢复、构建、发布)。这需要几分钟,整个管道几乎需要 30 分钟。

我的目标是优化构建时间。我想出了两种可能的并行方式:

  • 删除恢复和构建,运行只是发布(因为它恢复引用并执行与构建相同的操作)
  • 发布一次代码(适用于所有可运行的应用程序)并在 Dockerfiles 中复制二进制文件,无需再次构建

这两种方法都可行吗?我不知道如何使第二个工作 - 我是否应该为每个可运行的应用程序运行 dotnet publish,然后使用二进制文件收集文件夹中的所有 Dockerfile 并运行 docker build?我担心的是 - 我需要将所需的 .dll 文件复制到图像中,但是如何在不明确指定的情况下选择哪些文件?

编辑:

我正在使用 Linux 容器。我不编写我的 Dockerfile - 它们是由 Visual Studio 自动生成的。我给你举一个例子:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["Application.WebAPI/Application.WebAPI.csproj", "Application.WebAPI/"]
COPY ["Processing.Dependency/Processing.Dependency.csproj", "Processing.Dependency/"]
COPY ["Processing.QueryHandling/Processing.QueryHandling.csproj", "Processing.QueryHandling/"]
COPY ["Model.ViewModels/Model.ViewModels.csproj", "Model.ViewModels/"]
COPY ["Core.Infrastructure/Core.Infrastructure.csproj", "Core.Infrastructure/"]
COPY ["Model.Values/Model.Values.csproj", "Model.Values/"]
COPY ["Sql.Business/Sql.Business.csproj", "Sql.Business/"]
COPY ["Model.Events/Model.Events.csproj", "Model.Events/"]
COPY ["Model.Messages/Model.Messages.csproj", "Model.Messages/"]
COPY ["Model.Commands/Model.Commands.csproj", "Model.Commands/"]
COPY ["Sql.Common/Sql.Common.csproj", "Sql.Common/"]
COPY ["Model.Business/Model.Business.csproj", "Model.Business/"]
COPY ["Processing.MessageBus/Processing.MessageBus.csproj", "Processing.MessageBus/"]
COPY ["Processing.CommandHandling/Processing.CommandHandling.csproj", "Processing.CommandHandling/"]
COPY ["Processing.EventHandling/Processing.EventHandling.csproj", "Processing.EventHandling/"]
COPY ["Sql.System/Sql.System.csproj", "Sql.System/"]
COPY ["Application.Common/Application.Common.csproj", "Application.Common/"]
RUN dotnet restore "Application.WebAPI/Application.WebAPI.csproj"
COPY . .
WORKDIR "/src/Application.WebAPI"
RUN dotnet build "Application.WebAPI.csproj" -c Release -o /app

FROM build AS publish
RUN dotnet publish "Application.WebAPI.csproj" -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Application.WebApi.dll"]

还有一件事 - 问题是 azure devops 有这个构建映像的作业,我只是复制了这个作业 6 次,将每个副本指向其他 Dockerfile。这就是他们不重用代码的原因——我很想改变它,使它们基于相同的二进制文件。以下是 Azure DevOps 中的步骤:

  1. 获取来源
  2. 构建并推送映像编号。 1
  3. 构建并推送映像编号。 2
  4. 构建并推送映像编号。 3
  5. 构建并推送映像编号。 4
  6. 构建并推送映像编号。 5
  7. 构建并推送映像编号。 6

每个“构建和推送映像”都会:

  1. dotnet 恢复
  2. dotnet 构建
  3. dotnet 发布

我想摆脱这种开销 - 有可能吗?

【问题讨论】:

  • 你看过andrewlock.net/…吗?
  • 您是否为这种情况找到了一个好的解决方案?我有一个非常相似的问题。
  • 很遗憾我没有这样做,因为这需要一些我们当时没有的额外时间。

标签: docker asp.net-core azure-devops dotnet-cli


【解决方案1】:

如果没有看到您的 Dockerfile,很难说,但您可能会犯一些错误,这会增加映像构建的时间。例如,Dockerfile 中的每个命令都会产生一个层。 Docker 会缓存这些层,并且仅在该层或之前的层发生更改时才重建该层。

人们犯的一个非常常见的错误是复制他们的整个项目以及首先中的所有文件,然后运行dotnet restore。当您这样做时,对任何文件的任何更改都会使该复制层失效,因此dotnet restore 层也会失效,这意味着您必须在每次构建时都恢复包。 dotnet restore 唯一需要的是项目文件,所以如果你只复制那些,运行dotnet restore,然后复制所有文件,这些层将被缓存,除非项目文件本身发生变化。由于这通常仅在您更改包(添加、更新、删除等)时发生,因此大多数情况下,您不必重复恢复步骤,构建会更快。

在 Windows 上使用 npm 和 Linux 映像时可能会出现另一个问题。这是我个人的一点。为了支持 Linux 映像,Docker 使用 Linux VM (MobyLinux)。在构建开始时,Docker 将整个文件系统上下文(即运行docker 命令的位置)提升到 MobyLinux VM 中,首先,因为所有 Dockerfile 命令都将在 VM 中实际运行,因此文件将需要住在那里。如果您有一个node_modules 目录,则可能需要大量 时间来移动所有内容。您可以通过将node_modules 添加到您的.dockerignore 文件来解决此问题。

您可能还会犯其他类似类型的错误。我们真的需要查看您的 Dockerfile 以进一步帮助您。无论如何,您不应该采用您提出的任何一种方法。仅运行publish 将遇到上述相同的问题,并且此时您无法缓解问题。除非您非常小心,否则在图像之外发布可能会导致平台不一致和其他问题。它还在镜像构建过程中添加了一堆手动步骤,这破坏了 Docker 提供的许多好处。您的图像也会更大,除非您恰好在与图像将使用的架构完全相同的架构上发布。例如,如果您在 Windows 上进行开发,但使用的是 Linux 映像,则必须包含完整的 ASP.NET Core 运行时。如果您在映像中构建和发布,您可以只在构建和发布阶段包含 SDK,然后针对 alpine linux 之类的东西,使用自包含架构特定的发布。

【讨论】:

  • 请查看我编辑的帖子。只是想补充一下 - 我不是 Docker 新手,也许不是专家,但我知道我的方式,所以我熟悉层等等,不需要非常深入地解释东西:)
猜你喜欢
  • 1970-01-01
  • 2022-01-06
  • 1970-01-01
  • 2020-10-06
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多