Jack
Jack

Reputation: 10613

Standard Go Project Layout with Docker causes build context problem

I'm following two guides which appear to conflict

  1. Standard Go Project Layout
  2. Google Cloud Endpoints Sample for Go using gRPC

Go's Standard Go Project Layout recommends a /build directory, the use of which is described as

Packaging and Continuous Integration.

Put your cloud (AMI), container (Docker), OS (deb, rpm, pkg) package configurations and scripts in the /build/package directory.

Following Google Cloud Endpoints Sample for Go using gRPC, I have a Dockerfile which copies application source code and installs any dependencies with go get.

# /build/Dockerfile

FROM golang:alpine

# Alpine Linux package management
RUN apk update
RUN apk add git

COPY ../ /go/src/github.com/username/repository

# Downloads the packages named by the import paths, along with their
# dependencies. It then installs the named packages, like 'go install'.
# ****Don't do this in production! Use vendoring instead.****
RUN go get -v github.com/username/repository/foo-module

# Compiles and installs the packages named by the import paths.
RUN go install github.com/username/repository/foo-module

ENTRYPOINT ["/go/bin/foo-module"]

Following Standard Go Project Layout I place the aforementioned Dockerfile in /build.

Since the Dockerfile is now in the /build directory, I modified the COPY command to copy the parent directory to find the application source code (COPY ../ /go/src/github.com/username/repository).

The Docker build command is not run directly, rather the build is started with Google Cloud Build

cloud-build-local --config=build/cloudbuild.yaml .

The cloudbuild.yaml file is really simple and just kicks off the Docker build. The --file flag points to build/Dockerfile since the Cloud Build command is started from the project root and not from /build)

# /build/cloudbuild.yaml

steps:
    - id: Build
      name: "gcr.io/cloud-builders/docker"

      dir: ${_SOURCE}
      args:
        [
            "build",
            "--file build/Dockerfile",
            ".",
        ]

As expected, this fails

COPY failed: Forbidden path outside the build context: ../ ()

How to include files outside of Docker's build context? suggests using the --file flag, however, this assumes the build is started from the root context. When using Google's Cloud Build, the build is started from cloudbuild.yaml, which also located in /build.

I could just place the Docker file in the root of my go module, but I would like to follow best practices where possible and keep cloudbuild.yaml and Dockerfile in /build.

What is the correct way to achieve this while following the Standard Go Project Layout?

Upvotes: 2

Views: 1255

Answers (1)

BMitch
BMitch

Reputation: 263726

That's a rather long question, so lets focus on the problem encountered:

COPY ../ /go/src/github.com/username/repository

which resulted in

COPY failed: Forbidden path outside the build context: ../ ()

You don't include files outside of the context, docker doesn't allow that. Instead you change your context to include the files you need to build your image, and make the paths in your COPY/ADD commands relative to that context. Make sure to reread that, these paths are not relative to the Dockerfile location.

So with a docker build, if you have build/Dockerfile, you would build from the parent directory with:

docker build -f build/Dockerfile .

That trailing dot is the path to the build context which gets sent to the docker engine to perform the build. It doesn't access files directly on the client, which is why you can't include files from outside of the context (plus you don't want malicious Dockerfiles extracting data from the build server).

Then inside the Dockerfile you'd define the paths relative to that context:

COPY . /go/src/github.com/username/repository

And if for some reason you cannot build from that parent directory because of the tooling, then make the context the parent folder with a relative path:

docker build -f Dockerfile ..

Upvotes: 2

Related Questions