Search code examples
dockerazure-devopsdockerfileazure-task-groups

Azure DevOps Pipeline Dockerfile COPY --from clause


Problem

Working with Azure DevOps, we use a Dockerfile to build and statically serve an Angular application:

Dockerfile

FROM node:12-14-alpine AS build
WORKDIR /usr/etc/app
COPY *.json ./
RUN npm install
COPY . .
RUN npm run build -- -c stage

FROM node:alpine as runtime
WORKDIR /app
RUN yarn add express
COPY --from=build /usr/etc/app/dist/production ./dist
COPY --from=build /usr/etc/app/server.js .
ENV NODE_ENV=production
EXPOSE 8080
ENTRYPOINT ["node", "server.js"]

Locally, the container builds as expected. However, running this dockerfile (or a similar one) on the pipeline gives following output:

Pipeline Output

Starting: Build frontend image
==============================================================================
Task         : Docker
Description  : Build, tag, push, or run Docker images, or run a Docker command
Version      : 1.187.2
Author       : Microsoft Corporation
Help         : https://learn.microsoft.com/azure/devops/pipelines/tasks/build/docker
==============================================================================
/usr/bin/docker pull =build /usr/etc/app/server.js .
invalid reference format
/usr/bin/docker inspect =build /usr/etc/app/server.js .
Error: No such object: =build /usr/etc/app/server.js .
[]
/usr/bin/docker build -f /home/***/YYY/app/myagent/_work/1/s/Frontend/Dockerfile --label com.azure.dev.image.system.teamfoundationcollectionuri=XXXX --label com.azure.dev.image.build.sourceversion=6440c30bb386************d370f2bc6387 --label com.azure.dev.image.system.teamfoundationcollectionuri=
Sending build context to Docker daemon  508.4kB

Step 1/18 : FROM node:12.14-alpine AS build
...
# normal build until finish, successful

(note the duplicate teamfoundationcollectionuri labelling, but this is another issue)

Questions

We don't understand:

  1. how and why the first command is constructed (/usr/bin/docker pull =build /usr/etc/app/server.js .)
  2. how and why the second command is constructed (/usr/bin/docker inspect =build /usr/etc/app/server.js .)
  3. how the docker agent does not recognize the --from clause at first, but builds successfully (and correctly) nevertheless
  4. why the docker agent does warn about an invalid reference format but then goes on recognising every single instruction correctly.

btw, all these errors also happen when building the .NET backend (with a similar dockerfile).

We now DO understand that this problem only happens with task version 1.187.2 (or 0.187.2, see link below), but not with the previous 1.181.0 (resp. 0.181.0).

Additional Sources

all we could find about this problem is an old issue thread from 2018 that has been archived by microsoft. the only link is via the IP address, no valid certificate. The user has the exact same problem, but the thread was closed. Interestingly enough, the minor and patch version numbers are identical to our system.


Solution

  • Came across this question while searching for an answer to the same issue. I have spent the last few hours digging through source code for the Docker task and I think I can answer your questions.

    It appears that the Docker task tries to parse the Dockerfile to determine the base image, and there is (was) a bug in the task that it was looking for lines with FROM in them, but was incorrectly parsing the --from from the COPY --from line.

    It then passes that base image to docker pull and docker inspect prior to calling docker build. The first two commands fail because they're being passed garbage, but the third (docker build) reads the dockerfile correctly and does a pull anyway, so it succeeds.

    It looks like this was fixed on 2021-08-17 to only parse lines that start with FROM, so I assume it will make it to DevOps agents soon.