Search code examples
.netdockerazure-devopsdockerfiletopshelf

Dockerfile builds locally but fails on COPY step in Azure Devops pipeline


I've containerized a simple windows service running on .net framework 4.8. The app and container both build and run fine locally with this 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"]

When I connect to the container locally in docker desktop, I see the files in the C:/app directory that I expect and can confirm the service is operating as expected.

However, when I try to run this dockerfile in an pipeline in Azure Devops using a windows-latest build agent, I keep getting the following error on the COPY step:

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

Any ideas why this might be happening and how I can fix it?

EDIT: azure-pipelines.yml for the build:

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)

Solution

  • I don't think the COPY command does what you think it does. COPY copies files from the host file system into the container. The reason it works locally is because you've built the code locally, so it's copying the version you built locally into the container.

    What you should be doing is COPYing the source code into the container, then running whatever steps are necessary to build the application. It's also a good practice to use multi-stage builds for this: You copy the source code to a container with the SDK and your build toolchain, build it, then copy the resulting output into a slimmed down runtime container that just contains a runtime environment with no source code.