Go - Compiling Code in a Docker Image

Written by Paul Bradley

Using a docker image to compile your Go code with the latest version of Go.

midjourney ai - A samurai with pitch black skin standing in front of a deserted city

Why use Docker to compile Go code?

I’m using a Ubuntu LTS release for my main development machine and the version of Go that is included with the package manger is version 1.13.8. I had a need to compile a program using the latest version of Go which at the time of writing this is 1.19.3.

I could have updated my local development machine, but I wanted to see if I could use Docker to compile and compress my executable using the official Golang Image as a starting point.

Writing the Dockerfile

Below is the Dockerfile I came up with to compile my Lambda functions. Starting from the official 1.19.3 Golang Image I then update the Alpine packages and install Git, UPX and gcc.

I don’t like using modules, so the environment variable GO111MODULE=off forces Go behave in the GOPATH way, even outside of GOPATH. The other two environment variables allows me to compile the function for the ARM/Graviton Architecture.

 1FROM golang:1.19.3-alpine AS builder
 2
 3# update the packages and install
 4# git, upx and gcc
 5RUN apk update
 6RUN apk add --no-cache git
 7RUN apk add --update bash
 8RUN apk add --update upx
 9RUN apk add --update gcc musl-dev
10
11# set environment variables to control
12# which architecture to target
13ENV GO111MODULE=off
14ENV GOOS=linux
15ENV GOARCH=arm64
16
17# install Go packages required to build our project
18RUN go get github.com/aws/aws-lambda-go/events; exit 0
19RUN go get github.com/aws/aws-lambda-go/lambda; exit 0
20
21# make a directory called builder and copy
22# our Go source code into the directory
23RUN mkdir -p /go/src/builder
24ADD ./ /go/src/builder
25
26# compile the code and then compress the
27# executable with UPX to reduce its size
28RUN cd /go/src/builder && \
29    go build -tags="lambda.norpc" \
30             -ldflags="-w -s" \
31             -o /go/bin/bootstrap *.go && \
32    cd /go/bin/ && upx -9 bootstrap

After defining the environment variables, we install the Go packages needed for the project. Docker’s caching system means that these files need only to be downloaded once. Subsequent runs of the same Dockerfile will start from the ADD command, which copies our source code to the Docker image.

Lastly, we use the Docker RUN command to build the project and compress the executable.

Using the Dockerfile to compile Go code

Below is an example showing the sequence of Docker commands used to:

1docker build -t lambda -f ../build.Dockerfile .
2docker run --name "lambda" lambda /bin/bash
3docker cp lambda:/go/bin/bootstrap ./bootstrap
4docker rm lambda
5zip -9 main.zip bootstrap