Firmino Changani

Shipping a Go service as a Docker container

15 Aug 2023

At this day and age Docker has established itself as the de facto tool for containerisation, it is deserved given how well it abstract its complexity away from its users. In the cloud it allows us to run containerised services as if the programming language those services have been written on don't really matter, and in fact it doesn't, provided that the service are exposed on a port.

On this blog post I will my preferred set up to Dockerize Go services.

Binary, Binary, Binary

Binary, Binary, Binary - Steve Balmer

The command go build generates a binary, and this is a relevant and non-trivial fact that is going to impact how I am going to set up the Dockerfile, but I am going to come back at this later, for now here is the code snippet:

## Builder stage
FROM golang:1.20 AS builder


WORKDIR /usr/app
COPY . ./

RUN go build -buildvcs=false -o bin/service -ldflags="-X main.Version=${VERSION}" ./

## Final stage

FROM alpine
WORKDIR /usr/app
COPY --from=builder /usr/app/bin/service ./service

ENTRYPOINT ["./service"]


The Dockerfile above has two stages where the first stage is solely focused on building a binary from the source code:

After the binary gets built on the state named builder, Docker jumps into the second stage and does the following:

How to build it, and run it

To build a new Docker image versioned 0.0.1, run the following command:

docker build --build-arg VERSION=0.0.1 -t go-docker-demo:0.0.1 .

And to run the image newly built run the following command:

docker run -p 8080:8080 go-docker-demo:0.0.1


That's the end of this post, and perhaps to I would like to conclude that the fact that Go generates a binary that can be executed without an external runtime helps to build Docker images based in lightweight images such as alpine, which makes the build faster, and very cheap to host it on an Images Registry provided by a Cloud vendor, which tend to charge by data transferred in and out.

Cheers,<br/> Firmino