jean
jean

Reputation: 2980

write dockerfile for multiple go.mod project

There is a library writing in Go. Its folder structure is:

lib/
    golang/
        go.mod
        lib.go
        example/
            golang/
                proto/
                    protofile
                go.mod
                main.go
                Dockerfile

example is folder to show how to use this lib, so it has a main.go which can build and run. In order to use the lib, the example/golang/go.mod is:

module golang

go 1.15

require (
    lib/golang v0.0.0
    other stuff...
)

replace lib/golang => ../../golang
    

Now I want to pack the runnable example into a docker image, the Dockerfile is:

FROM golang:1.15

WORKDIR /go/src/app
COPY . .

RUN go env -w GO111MODULE=auto
RUN go env -w GOPROXY=https://goproxy.io,direct

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

Then I cd into example/golang run docker build -t example ., the error log is

open /go/golang/go.mod: no such file or directory

It seems can not access lib/go.mod file, then I cd into lib folder and run docker build -t server -f examples/golang/Dockerfile ., however this will affect the import of main.go:

import "golang/proto"

error log is:

golang/proto: unrecognized import path "golang/proto"

How should I fix this to make the docker image?

==========================================

After I spend some time to read docker doc, here is the summary about this problem:

docker build command follow a PATH argument, that is the dot . at the end. That control the content of building, it decides what files docker build can access. So the reason of first error is that the pwd is lib/example/golang, and docker build command path is ., then docker build can not access parent files of lib/example/golang and they are required in main.go as a lib. the command should be: docker build -t example ../../ However, docker build seek Dockerfile only in root of content path, so use -f to tell it where the Dockerfile located: docker build -t example -f ./Dockerfile ../../

if pwd is lib/, command is docker build -t server -f examples/golang/Dockerfile .

Be short:

  1. If the dockerfile is not located at project root path, use -f and PATH of docker build command to give it enough access of files. If using go module, make sure PATH contain a go.mod file
  2. If main.go is located in sub folder, make sure the WORKDIR in dockerfile same as the sub folder after COPY all need, or else go build or go install fail to compile

Upvotes: 2

Views: 2180

Answers (2)

t0mpl
t0mpl

Reputation: 5025

You can use go mod vendor before to build with Docker, it will centralise all your mod in vendor folder.

I did a a new file called build.sh with this inside:

#! /bin/sh
go mod vendor
docker build . -t myapp/myservice
rm -rf ./vendor

and run it whenever i need to build and by deleting vendor i can still use go run *.go with fresh version of my libraries

Upvotes: 1

colm.anseo
colm.anseo

Reputation: 22027

Your Dockerfile is too nested. Since your go build relies on relative paths - paths that are in parent directories - a docker build . will not see any parent-directory files.

Move the Dockerfile to the top e.g.

Dockerile
lib/

and update to build the nested build directory:

FROM golang:1.15

WORKDIR /go/src/app

# just need to copy lib tree
COPY lib .  

# working from here now
WORKDIR /go/src/app/lib/golang/example/golang 

RUN go env -w GO111MODULE=auto    
RUN go env -w GOPROXY=https://goproxy.io,direct

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

Upvotes: 4

Related Questions