Cannot locate docker build output of multistage build inside CodeBuild

Viewed 175

We're using a aws/codebuild/standard:5.0 codebuild image to build our own docker images. I have a buildspec that calls docker build against our Dockerfile and push to ECR. The Dockerfile uses Microsoft dotnet base images to call dotnet pubish to build our binaries. This all works fine.

We then added a build stage to our Dockerfile to run unit tests (using dotnet test) and we followed the "FROM scratch" advice combined with docker build --output to try and pull unit test results files out of the multi-stage target:

      docker build --target export-test-results -f ./Dockerfile --output type=local,dest=out .

This works fine locally (an out dir is created containing the files), but when I run this in Codebuild, I cannot find where the output may be (the command succeeds - but I've no idea where it's going). I've added ls commands everywhere, and cannot locate the out dir, so of course my artifacts step has nothing to archive.

Question is: where is the output being created inside the CodeBuild instance?

My (abbreviated) Dockerfile

ARG VERSION=3.1-alpine3.13

FROM mcr.microsoft.com/dotnet/aspnet:$VERSION AS base
WORKDIR /usr/local/bin

FROM mcr.microsoft.com/dotnet/sdk:$VERSION AS source

#Using pattern here to bypass need for recursive copy from local src folder: https://github.com/moby/moby/issues/15858#issuecomment-614157331
WORKDIR /usr/local
COPY . ./src

RUN mkdir ./proj && \
    cd ./src && \
    find . -type f -a \( -iname "*.sln" -o -iname "*.csproj" -o -iname "*.dcproj" \) -exec cp --parents "{}" ../proj/ \;

FROM mcr.microsoft.com/dotnet/sdk:$VERSION AS projectfiles
# Copy only the project files with correct directory structure
# then restore packages - this will mean that "restore" will be saved in a layer of its own
COPY --from=source /usr/local/proj /usr/local/src

FROM projectfiles AS restore
WORKDIR /usr/local/src/Postie
RUN dotnet restore --verbosity minimal -s https://api.nuget.org/v3/index.json Postie.sln

FROM restore AS unittests
#Copy all the source files
COPY --from=source /usr/local/src /usr/local/src
RUN cd Postie.Domain.UnitTests && \
        dotnet test --no-restore --logger:nunit --verbosity normal || true

FROM scratch as export-test-results
COPY --from=unittests /usr/local/src/Postie/Postie.Domain.UnitTests/TestResults/TestResults.xml ./Postie.Domain.UnitTests.TestResults.xml

My (abbreviated) Buildspec:

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY_SERVER
  build:
    commands:
      - export IMAGE_TAG=:$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7).$CODEBUILD_BUILD_NUMBER
      - export JENKINS_TAG=:$(echo $JENKINS_VERSION_NUMBER | tr '+' '-')
      - echo Build started on `date` with version $IMAGE_TAG
      - cd ./Src/
      - echo Testing the Docker image...
        #see the following for why we use the --output option
        #https://docs.docker.com/engine/reference/commandline/build/#custom-build-outputs
      - docker build --target export-test-results -t ${DOCKER_REGISTRY_SERVER}/postie.api${IMAGE_TAG} -f ./Postie/Postie.Api/Dockerfile --output type=local,dest=out .

artifacts:
  files:
    - '**/*'
  name: builds/$JENKINS_VERSION_NUMBER/artifacts

(I should note that the "artifacts" step above is actually archiving my entire source tree to S3 so that I can prove that the upload is working and also so that I can try to find the "out" dir - but it's not to be found)

1 Answers

I know this is old, but just in case anyone else stumbles across this one, you need to add the Docker Buildkit variable to the CodeBuild environment, otherwise the files will not get exported.

version: 0.2
... etc
phases:
  build:
    commands:
    ... etc
    - echo Testing the Docker image...
    - export DOCKER_BUILDKIT=1
    - docker build --target export-test-results ... etc
... etc

If you want to display more output along with this you can also add

- export BUILDKIT_PROGRESS=plain
- export PROGRESS_NO_TRUNC=1

under the buildkit variable.

Related