How to use go mod with local package and docker?
Asked Answered
T

2

7

I have two go modules github.com/myuser/mymainrepo and github.com/myuser/commonrepo

Here is how i have the files in my local computer

- allmyrepos  
 - mymainrepo
   - Dockerfile
   - go.mod
 - commonrepo
   - go.mod

mymainrepo/go.mod

...
require (
  github.com/myuser/commonrepo
)

replace (
  github.com/myuser/commonrepo => ../commonrepo
)

It works well i can do local development with it. Problem happens when i'm building docker image of mymainrepo

mymainrepo/Dockerfile

...
WORKDIR /go/src/mymainrepo

COPY go.mod go.sum ./
RUN go mod download


COPY ./ ./
RUN go build -o appbinary
...

Here replace replaces github.com/myuser/commonrepo with ../commonrepo but in Docker /go/src/commonrepo does not exists.

I'm building the Docker image on CI/CD which needs to fetch directly from remote github url but i also need to do local development on commonrepo. How can i do both ?

I tried to put all my files in GOPATH so it's ~/go/src/github.com/myuser/commonrepo and go/src/github.com/myuser/mymainrepo. And i removed the replace directive. But it looks for commonrepo inside ~/go/pkg/mod/... that's downloaded from github.

Taster answered 7/5, 2020 at 12:24 Comment(1)
Were you able to resolve the issue? I have the exact same problem. Can you please share your Dockerfile?Throaty
G
5

Create two go.mod files: one for local development, and one for your build. You can name it go.build.mod for example.

Keep the replace directive in your go.mod file but remove it from go.build.mod.

Finally, in your Dockerfile:

COPY go.build.mod ./go.mod
COPY go.sum ./
Gauze answered 7/5, 2020 at 17:55 Comment(6)
ok. But what if I want to keep the 'replace' for the build also, is there a way without creating 2 go.mod files?Eisenach
@ArjunAjith not as far as I know. But if the replace are the same for both, simply use one .mod file and copy the required resources during your image build steps.Gauze
I'd say your solution won't work for this specific question. Probably the OP wants to have the local changes of "../commonrepo" within the container, and not the version specified in the other go.mod, which likely will point to a valid go module, but with a totally different changesVelvetvelveteen
after that when someone doing go get ... how do you make sure the package also going to go.build.mod file? they will need to remember every time to add it manual?Lands
I am using two local project with replace: github.com/rafaelsouzaribeiro/logs => ../logs replace github.com/rafaelsouzaribeiro/producer => ../producer And I "go get" each one to make it work. I'm using version: go1.22.0 Will my containers still not recognize local projects?Periclean
@Slim Shady What is the solution to the problem? thanksPericlean
K
5

I still can't find other better solution even the voted answer doesn't work for me. Here a trick I've done that workaround for me. This is an example structure for doing this:

|---sample
|   |---...
|   |---go.mod
|   |---Dockerfile
|---core
|   |---...
|   |---go.mod
  1. We know that docker build error when it can't find our local module. Let's make one in the builder process:
# Use the offical golang image to create a binary.
# This is based on Debian and sets the GOPATH to /go.
# https://hub.docker.com/_/golang
FROM golang:1.16.3-buster AS builder

# Copy core library
RUN mkdir /core
COPY core/ /core

# Create and change to the app directory.
WORKDIR /app

# Retrieve application dependencies.
# This allows the container build to reuse cached dependencies.
# Expecting to copy go.mod and if present go.sum.
COPY go.* ./
RUN go mod download

# Copy local code to the container image.
COPY . ./

# Build the binary
RUN go build -o /app/sample cmd/main.go
...
...

Ok, our working dir is /app and our core lib placed next to it /core.

  1. Let's make a trick when build a docker image! Yeah, you know it.
cp -R ../core . && docker build --tag sample-service . && rm -R core/

Update A way better, create a Makefile next to Dockerfile, with content below:

build:
    cp -R ../core .
    docker build -t sample-service .
    rm -R core/

Then command, make build in the sample directory.

You can create make submit or make deploy commands as you like to.

=> Production ready!

Be aware that if there's an error occurs during docker build process, it won't delete back the core folder we have copied to sample.

Pls let me know if you find any better solution. ;)

Kial answered 8/5, 2021 at 4:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.