Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract file from multistage Docker build

In a multistage docker build I execute unit tests, generate a coverage report and build an executable in a build stage and then copy the executable over to an run stage:

FROM golang:1.13 AS build-env
COPY . /build
WORKDIR /build

# execute tests
RUN go test ./... -coverprofile=cover.out
# execute build
RUN go build -o executable

FROM gcr.io/distroless/base:latest
COPY --from=build-env /build/executable /executable
ENTRYPOINT ["/executable"]

How can I extract the cover.out in a Jenkins environment to publish the coverage report?

like image 424
Christopher Avatar asked Dec 13 '19 22:12

Christopher


2 Answers

With Docker 17.05, the only options I know of have been posted: refactoring to run the step with a run command and volume mount, or as you've done, docker cp. Each option requires building the specific build target with the --target option, which I suspect was your original question.

With BuildKit in 19.03, there's an option to build something other than an image. That would look like:

# import code
FROM golang:1.13 AS code
COPY . /build
WORKDIR /build

# execute tests
FROM code as test
RUN go test ./... -coverprofile=cover.out

# execute build
FROM code as build
RUN go build -o executable

# add a stage for artifacts you wish to extract from the build
FROM scratch as artifacts
COPY --from test /build/coverage.xml /
COPY --from test /build/report.xml /

# and finally the release stage
FROM gcr.io/distroless/base:latest as release
COPY --from=build /build/executable /executable
ENTRYPOINT ["/executable"]

Then your build command looks like:

mkdir -p artifacts
DOCKER_BUILDKIT=1 docker build -o type=local,dest=artifacts/. --target artifacts .
DOCKER_BUILDKIT=1 docker build -t myapp .

The important detail there is the --output or -o option that specifies what BuildKit should do with the resulting image. By default it is imported back into the local docker engine. But in this case, it writes the result out to the local filesystem.

like image 163
BMitch Avatar answered Sep 30 '22 00:09

BMitch


You should run tests using a Docker Compose file so that its easy to non-interactively extract outputs, and so that build logic is separated from the rest of the pipeline (not to mention it's faster).

You should use a docker-compose.yml with a bind mount to the $PWD. Here's a snippet from said Docker Compose file which will mirror the outputs to your host machine:

version: '3.7'
services:
  app:
    image: golang:1.13
    command: go test ./... -coverprofile=cover.out
    volumes:
      - type: bind
        source: .
        target: /app

The artifacts can now be saved as you normally would in your CI pipeline.

like image 32
Neel Kamath Avatar answered Sep 29 '22 22:09

Neel Kamath