Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create docker container to run `go test` with all module dependencies downloaded and cached

Tags:

docker

go

I want to test my Go code in a CI environment which requires using Docker. How do I create a Docker image that has all the dependencies listed in go.mod already downloaded and compiled so that docker run $IMG go test uses the cached artifacts?

The desired properties of this image:

  • The image only uses go.mod to compile dependencies. I don't want to use the full source code because then any change to source code would invalidate the Docker layer that hold cached dependencies.

  • docker run $IMG go test ./... doesn't redownload or recompile dependencies listed in go.mod.

  • Avoid experimental Docker features.

Existing approaches

Parsing go.mod and using go get

From https://github.com/golang/go/issues/27719#issuecomment-578246826

This approach is close but it doesn't appear to use GOCACHE when I run go test. This also appears to choke on certain module paths, like gopkg.in/DataDog/dd-trace-go.v1:

FROM golang:1.13
WORKDIR /src
COPY go.mod ./
RUN set -eu \
  && go mod graph \
  | cut -d '@' -f 1 \
  | cut -d ' ' -f 2 \
  | sort -u \
  | sed -e 's#dd-trace-go.v1#&/ddtrace#' \
  | xargs go get -v
docker run --mount /src:/src $IMG go test ./...

Using DOCKER_BUILDKIT with a mount cache

Originally described in https://github.com/golang/go/issues/27719#issuecomment-514747274. This only works for go build. I can't use it for go test because the cache mount is unmounted after the RUN command so it doesn't exist in the created Docker image.

This also depends on experimental docker features.

# syntax = docker/dockerfile:experimental
FROM golang:1.13 as go-builder
ARG VERSION
WORKDIR /src
COPY . /src/
# With a mount cache, Docker will cache the target directories for future
# invocations of this RUN layer. Meaning, once this command is run once, all
# successive calls will use the already downloaded and already compiled assets.
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build ./server
like image 383
Joe Avatar asked Feb 13 '20 04:02

Joe


People also ask

Does Docker image contain all dependencies?

Since the image contains the container's filesystem, it must contain everything needed to run an application - all dependencies, configurations, scripts, binaries, etc. The image also contains other configuration for the container, such as environment variables, a default command to run, and other metadata.

Can Docker encapsulate any payload and its dependencies?

Docker containers can encapsulate any payload, and will run consistently on and between virtually any server. The same container that a developer builds and tests on a laptop will run at scale, in production, on VMs, bare-metal servers, public instances, or combinations of the above.

Can you run guis in Docker?

Follow the below steps to run a GUI application inside Docker: Step 1: Install and Start Docker and check the status and restart the service. The Systemctl commands are used to manage system services. systemctl start docker // to start the docker service.


1 Answers

I often put COPY go.mod on the very begin of a Dockerfile, as it does not change that often.

FROM golang:1.14.3 as builder

WORKDIR /app

COPY go.mod .
COPY go.sum .

RUN go mod download

COPY . .
RUN go build -tags netgo -ldflags '-extldflags "-static"' -o app .

FROM centos:7  
WORKDIR /root

COPY --from=builder /app/app .

So, if you go mod does not change, the line RUN go mod download only run for the first time.

like image 133
Arith Avatar answered Sep 22 '22 15:09

Arith