【问题标题】:Dockerfile builds locally but fails on COPY step in Azure Devops pipelineDockerfile 在本地构建,但在 Azure Devops 管道中的 COPY 步骤失败
【发布时间】:2020-11-22 04:33:13
【问题描述】:

我已经容器化了一个在 .net 框架 4.8 上运行的简单 Windows 服务。使用这个 dockerfile,应用程序和容器都可以在本地构建和运行:

FROM ourcontainerregistry.azurecr.io/net-framework-base:latest
WORKDIR /app

RUN cmd MSBuild.exe /property:Configuration=Release
COPY TopShelfServiceInstaller/bin/Release/ .

ENTRYPOINT ["TopShelfServiceInstaller.exe"]

当我在 docker 桌面本地连接到容器时,我在 C:/app 目录中看到了我期望的文件,并且可以确认服务正在按预期运行。

但是,当我尝试使用 Windows 最新的构建代理在 Azure Devops 的管道中运行此 dockerfile 时,我在 COPY 步骤中不断收到以下错误:

COPY failed: CreateFile \\?\C:\ProgramData\docker\tmp\docker-builder002424695\TopShelfServiceInstaller\bin\Release: The system cannot find the path specified.

任何想法为什么会发生这种情况以及我该如何解决?

编辑:用于构建的 azure-pipelines.yml:

resources:
  repositories:
    - repository: net-framework-base
      type: git
      name: Container_DotNetFrameworkBase
  containers:
    - container: net-framework-base
      type: ACR
      azureSubscription: ---
      resourceGroup: ---
      registry: ---
      repository: net-framework-base

variables:
  - name: dockerRegistryServiceConnection
    value: ---
  - name: imageRepository
    value: "service"
  - name: containerRegistry
    value: ---
  - name: prod-container-registry
    value: ---
  - name: dockerfilePath
    value: "$(Build.SourcesDirectory)/Service/dockerfile"
  - name: tag
    value: "$(Build.BuildNumber)"
  - name: vmImageName
    value: "windows-latest"
trigger:
  batch: true
  branches:
    include:
      - feature/*
#pr:
stages:
  - stage: container
    displayName: New Docker Build
    dependsOn: []
    jobs:
      - job: container
        displayName: build container
        pool:
          vmImage: $(vmImageName)
        steps:
          - checkout: self
            fetchDepth: 1
          - checkout: net-framework-base
            fetchDepth: 1

          # this is the task that's failing
          - task: Docker@2
            displayName: build container
            inputs:
              containerRegistry: $(prod-container-registry)
              repository: $(imageRepository)
              command: "build"
              Dockerfile: $(dockerfilePath)
              tags: |
                $(tag)

【问题讨论】:

  • 我不认为COPY 命令做你认为它做的事。 COPY 将文件主机文件系统复制到容器中。

标签: .net docker azure-devops dockerfile topshelf


【解决方案1】:

我认为COPY 命令不会像您认为的那样做。 COPY 将文件主机文件系统复制到容器中。它在本地工作的原因是因为您已经在本地构建了代码,所以它将您在本地构建的版本复制到容器中。

应该做的是COPY将源代码放入容器中,然后运行构建应用程序所需的任何步骤。使用multi-stage builds 也是一个很好的做法:您将源代码复制到带有 SDK 和构建工具链的容器中,构建它,然后将生成的输出复制到一个精简的运行时容器中,该容器只包含一个运行时环境没有源代码。

【讨论】:

  • 在这种情况下,构建代理是主机,对吧?我的印象是构建代理从我的存储库中检查源代码,在代理上构建解决方案,以便构建工件存在于那里,然后我可以只复制从 bin 运行应用程序所需的内容构建代理(主机)到容器中。
  • @Jerreck 虽然您可以这样做,但您不应该——任何人都应该能够克隆您的存储库并从头开始构建容器使用单个命令,无需预先构建应用程序代码。如果这是您尝试采用的方法,则需要确保您的构建管道正在构建代码。代理不会自动执行任何操作,由您来定义构建过程。由于您没有分享有关构建过程的详细信息,因此我无法提供任何建议。
  • 知道了,我的 dockerfile 和 azure-pipelines.yml 都与 .sln 一起存在于服务的存储库的根目录中。您可以通过运行 docker build 克隆存储库并从头开始构建容器。 yaml 指示构建代理运行与我在本地运行的完全相同的命令。我将更新我的问题以显示 yaml。
  • 我想要说明的一点是,您应该需要运行的only 命令是docker build。您不必运行其他任何东西。如果您的容器已经在构建应用程序,那么您不需要 Dockerfile 中的COPY 命令。
  • 更新了问题,但我想我明白你现在在说什么了。当我应该让代理构建源代码时,我正在让 dockerfile 构建源代码,这就是它失败的原因 - 代理没有构建它,所以它没有什么可复制的。
【解决方案2】:

我想添加另一个答案,以更好地解释我的问题是什么以及我是如何解决的。我的问题不是对 COPY 命令的误解,而是对在哪里构建的内容的误解。这是旧的 dockerfile,其中解释了我哪里出错了:

FROM ourcontainerregistry.azurecr.io/net-framework-base:latest
WORKDIR /app

# As Daniel said, the reason it was working for me locally is because I had already built the solution from visual studio.
# So this command wasn't actually building anything because nothing existed on this container yet.
RUN cmd MSBuild.exe /property:Configuration=Release

# However, this was copying the files I had already built in VS locally.
# When this ran on the build agent in Azure DevOps, it would fail because the solution had not been built on the build agent.
COPY TopShelfServiceInstaller/bin/Release/ .

ENTRYPOINT ["TopShelfServiceInstaller.exe"]

这是我的新 dockerfile,它使用带有 cmets 的多阶段构建,讲述了发生的时间和原因:

# First stage is building the app.  
# We do this with one container based on the .NET Framework 4.8 image that has the SDK installed on it.
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8-windowsservercore-ltsc2019 AS build
WORKDIR C:/build

# Next we copy all files from the host into the build container.
COPY . .

# Then we run MSBuild to build the solution.
RUN MSBuild.exe /property:Configuration=Release

# Next and last stage is creating a container that will actually run the app.
FROM ourcontainerregistry.azurecr.io/net-framework-base:latest AS runtime
WORKDIR C:/app

# And here we're copying files from the build container into the runtime container.
COPY --from=build C:/build/TopShelfServiceInstaller/bin/Release .

ENTRYPOINT [ "C:/app/TopShelfServiceInstaller.exe" ]

以这种方式构建的要点在于,它允许您克隆存储库并使用单个命令构建容器,无论您是在本地工作还是在自动构建管道中运行它,正如 Daniel 所提到的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 2022-11-03
    • 2021-01-03
    • 2020-01-01
    • 2019-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多