Dockerfile在本地生成,但在Azure Devops管道中的COPY步骤上失败

时间:2020-08-01 15:25:42

标签: .net docker azure-devops dockerfile topshelf

我已经容器化了一个在.net framework 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)

2 个答案:

答案 0 :(得分:1)

我不认为COPY命令会执行您认为的操作。 COPY将文件从主机文件系统复制到容器中。它在本地工作的原因是因为您是在本地构建代码的,所以它将本地构建的版本复制到容器中。

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

答案 1 :(得分:0)

我想添加另一个答案,以更好地解释我的问题以及如何解决。我的问题不是对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,它使用多阶段构建,并附有关于何时以及为什么发生的注释:

# 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所述。