1

[EDIT - added clarity]

Here is my current env setup :

  • $GOPATH = /home/fzd/go
  • projectDir = /home/fzd/go/src/github.com/fzd/amazingo

amazingo has a go.mod file that lists several (let's say thousands) dependencies.

So far, I used to go build -t bin/amazingo cmd/main.go, but I want to share this with other people and have a build command that is environment-independent. Using go build has the advantage of downloading each dependency once -- and then using those in ${GOPATH}/pkg/mod, which saves time and bandwidth.

I want to build in a multistage docker image, so I go with

> cat /home/fzd/go/src/github.com/fzd/amazingo/Dockerfile

FROM golang:1.17 as builder
COPY . . 
RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/amazingo cmd/main.go 

FROM alpine:latest
COPY --from=builder /bin/amazingo /amazingo
ENTRYPOINT ["/amazingo"]

As you can expect it, the builder is "naked" when I start it, so it has to download all my dependencies when I docker build -t amazingo:0.0.1 . . But it will do so everytime I call it, which can be several times a day.

Fortunately, I already have most of these dependencies on my disk. I would be happy to share these files (that are located in my $GOPATH/pkg/mod) with the builder, and help it build faster on my machine.

So the question is: how can I share my ${GOPATH} (or ${GOPATH}/mod/pkg) with the builder ?

I tried adding the following to the builder

ARG SRC_GOPATH
COPY ${SRC_GOPATH} /go

and call docker build --build-arg SRC_GOPATH=${GOPATH} -o amazingo:0.0.1 ., but it wasn't good enough - I got an error (COPY failed: file not found in build context or excluded by .dockerignore: stat home/fzd/go: file does not exist)

I hope this update brings a bit more clarity to the problem.

=======

I have a project with a go.mod file. I want to build that project using a multistage docker image. (this article is a perfect example)

The issue is that I have "lots" of dependencies, and each of them will be downloaded inside my Docker builder stage.

Is there a way to "share" my GOPATH/pkg/mod with the docker build... command (in some ways, having a local cache) ?

fzd
  • 765
  • 1
  • 6
  • 19
  • Did you try copying GOPATH from the previous stage? – JimB Oct 29 '21 at 14:06
  • Does this answer your question? [Manually fetch dependencies from go.mod?](https://stackoverflow.com/questions/52266332/manually-fetch-dependencies-from-go-mod) – rustyx Oct 29 '21 at 15:24
  • Edited the initial message to give more insights on what I'mt trying to do. @JimB I couldn't copy the GOPATH (see edited message above) – fzd Oct 29 '21 at 17:55
  • @rustyx No, what I want to do is not to get the deps manually, I really want to use those I have in my computer instead of downloading them everytime I run `docker build`. I've edited the initial message to make this clearer. – fzd Oct 29 '21 at 17:56
  • You cannot share a local folder with a build command. But what's the issue exactly? The linked question provides a solution that downloads the dependencies *once* and caches them in a docker layer, and re-downloads whenever go.mod changes. – rustyx Oct 29 '21 at 22:33
  • I don't want to download everything when I add a single dependency in the go.mod file – fzd Oct 31 '21 at 16:45

1 Answers1

0

Your end goal isn't completely clear, but the way that I use a multistage build would look something like this for a (dirt-simple) go app, assuming that you ultimately want the docker container to run your go app. You will need to get your source into the build container somehow as well - that is not shown here:

FROM golang:1.17.2-alpine3.14 as builder

WORKDIR /my/app/source/dir
RUN go get && go build -o /path/to/my/app/binary

FROM alpine3.14 AS release

# install runtime deps, if any
# create necessary files and folders, if any

COPY --from=builder /path/to/my/app/binary /usr/local/bin

ENTRYPOINT /usr/local/bin/binary --options

In this way, the source of your application and all dependencies will not be present in the released image, only the compiled binary.

Of course you don't have to specify an output path for that, I think it just makes it a little clearer in this example. And of course you can use whatever base image/images you want to - I'm treating this as though you don't need the go runtime on your release image.

trey-jones
  • 3,329
  • 1
  • 27
  • 35
  • you didn't copy anything into the builder – erik258 Oct 29 '21 at 16:00
  • As @DanielFarrell said, nothing was copied into the builder here. The `RUN go get` will indeed download things into the container - but these things might have already been present on my machine. I want to make use of these files rather than re-downloading everything everytime. My call to this Dockerfile is a `docker build [args]`. I can't `-v ${SRC}:${DEST}` with this command, so I need something else. Copying the entire GOPATH is overkill and could take too long, but I'm afraid that might be the only option. – fzd Oct 29 '21 at 17:34