无需在每个Dockerfile中构建二进制文件即可构建多个Docker映像

时间:2019-09-05 10:04:20

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

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

现在我要做的是逐个映像构建,这6个Dockerfile中的每一个都从头开始构建解决方案(还原,构建,发布)。这需要几分钟,整个流程几乎要花30分钟。

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

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

两种方法都可行吗?我不知道如何使第二个工作正常-我应该为每个可运行的应用程序运行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发布

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

1 个答案:

答案 0 :(得分:0)

很难看到您的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。