2

I'm trying to get to grips with working with workspaces in go 1.18, and how to make it work well in a monorepo.

As a minimum example, I have the following project structure:

.
├── docker-compose.yml
├── go.work
├── makefile
└── project
    ├── go.mod
    ├── module1
    │   ├── Dockerfile
    │   ├── go.mod
    │   └── main.go
    ├── module2
    │   ├── Dockerfile
    │   ├── go.mod
    │   └── main.go
    └── shared-module
        ├── go.mod
        └── shared.go

module1 and module2 can both be built into binaries with their respective main.go files. However, module1 uses shared-module, but module2 does not.

When building the binaries without Docker, I can cd into module1 or module2 and run go build and everything works fine. However problems occur when I want to use Docker for the builds.

Here is the Dockerfile for module1:

# FIRST STAGE
FROM golang:1.18 AS builder

WORKDIR /app/

# copy workfiles
COPY go.* ./

WORKDIR /app/project/

# dependency management files
COPY project/go.* ./
COPY project/module1/go.* ./module1/
COPY project/shared-module/go.* ./shared-module/

WORKDIR /app/project/module1/

RUN go mod download

WORKDIR /app/project/

# copy shared module
COPY project/shared-module/ ./shared-module/

# copy module to compile
COPY project/module1/ ./module1/

WORKDIR /app/project/module1/

RUN CGO_ENABLED=0 GOOS=linux go build -o bin/module1

# SECOND STAGE
FROM alpine:3.14.2
WORKDIR /app

COPY --from=builder /app/project/module1/bin/module1 /app

ENTRYPOINT [ "./module1" ]

With this build i'm trying to maximise caching by specifying files which change infrequently first. I'm also excluding any files which I don't need for the module (like module2).

Running docker-compose build module1 to build the image using that Dockerfile, the build fails with error:

go: open /app/project/module2/go.mod: no such file or directory

This initially surprised me, as module2 is not a dependency of either module1, or shared-module, but after a bit of consideration I realised it was because of the go.work file which specifies ./project/module2. Removing the line in go.work that specifies that module allows the image to be built successfully.

My question is therefore, if I want to have streamlined image builds, do I have to create multiple go.work files for each of the modules I want to build in Docker? For example, I would need another go.work file for module2 which omits module1 and shared-module.

テッド
  • 776
  • 9
  • 21
  • `go.work` files allow for rapid development when you don't want to edit the source controlled `go.mod`. if there is a blend of build that differe from the default (what's defined in `go.mod`) - then you will need a `go.work` for that build blend. If there's another blend you also need, then yes you'll need another `go.work`. Best to organize these into logically named directories for clarity. – colm.anseo Jul 15 '22 at 11:59

0 Answers0