The aim of multi stage builds is to keep the final application image as small as possible which is what we are going to do here. Also I'll show you vendor and non-vendor version build as well. It's up to you to pick one over another but so far I never needed to use vendor version because Go has been good at dependency management.


Structure


.
├── cmd
│   └── football
│   └── main.go
├── docker
│   └── dev
│   ├── docker-compose.yaml
│   └── go
│   └── Dockerfile
├── .env.dist
├── go.mod
├── go.sum
└── Makefile

docker-compose.yaml


version: "3.4"

services:

football-go:
container_name: "football-go"
hostname: "football-go"
build:
context: "../.."
dockerfile: "docker/dev/go/Dockerfile"
restart: "unless-stopped"
volumes:
- "../../.env.dist:/.env"

Non-vendor version


Dockerfile


#
# STAGE 1: prepare
#
FROM golang:1.13.1-alpine3.10 as prepare

WORKDIR /source

COPY go.mod .
COPY go.sum .

RUN go mod download

#
# STAGE 2: build
#
FROM prepare AS build

COPY . .

RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/football -v cmd/football/main.go

#
# STAGE 3: run
#
FROM scratch as run

COPY --from=build /source/bin/football /football

ENTRYPOINT ["/football"]

Build and run


Assuming that these commands as part of your Makefile file.


// Prune unused packages and dependencies from go.mod file.
$ go mod tidy -v

// Compile packages and dependencies then run the app.
$ go build -race -ldflags "-s -w" -o bin/football cmd/football/main.go
$ bin/football

Vendor version


Dockerfile


In this case there has to be vendor folder in the application root. For that you should have run two additional commands as mentioned at the bottom so that the exact dependencies could be copied over.


#
# STAGE 1: prepare
#
FROM golang:1.13.1-alpine3.10 as prepare

WORKDIR /source

COPY vendor .

#
# STAGE 2: build
#
FROM prepare AS build

COPY . .

RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/football -v cmd/football/main.go

#
# STAGE 3: run
#
FROM scratch as run

COPY --from=build /source/bin/football /football

ENTRYPOINT ["/football"]

Build and run


Assuming that these commands as part of your Makefile file.


// Prune unused packages and dependencies from go.mod file.
$ go mod tidy -v

// Reset vendor directory to include all dependencies and rebuild.
$ go mod vendor
$ go build -mod vendor ./...

// Compile packages and dependencies then run the app.
$ go build -race -ldflags "-s -w" -o bin/football cmd/football/main.go
$ bin/football