Build tiny containers for a go application

Containers are a mighty tool to package and distribute an application outside of the normal scope of a Linux distribution. However, most containers are HUGE. In this short blog post I show you, how to make a tiny container for your awesome go application.

Minimal size containers for go applications

So, you hacked this amazing go application and would like to distribute it to your people (TM). IMHO, for small applications a good way of creating minimal footprint containers is to create static binaries, and build a container from scratch, i.e. no base container.

So, for your application is prog.go, you can use the following Dockerfile:

FROM golang:alpine AS builder
WORKDIR /app
ADD . /app
RUN apk update && apk add build-base
RUN cd /app && CGO_ENABLED=0 go build -ldflags="-w -s" -o prog prog.go

FROM scratch
WORKDIR /app
COPY --from=builder /app/prog /app/awesome-prog
ENTRYPOINT ["/app/awesome-prog"]

Now let’s build the container with docker build . -t feldspaten.org/prog. Here docker first creates a build environment named builder, which is based on the alpine-golang container, and builds your go application therein. Mind the flags for building a static application:

CGO_ENABLED=0 go build -ldflags="-w -s" -o prog prog.go

This is only the building container. The resulting container is however based on scratch, thus no base container. All it contains is the statically linked binary and no further dependencies. This dramatically reduces the size of the whole container to run.

Here, the resulting container was 1.46MB in size:

$ docker image ls
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
feldspaten.org/prog   latest    53397fccbffc   47 minutes ago   1.46MB

Now let’s also try out our brand new container:

$ docker run -ti --rm feldspaten.org/prog
awesome go application is running

Awesome!

And that’s how you can create minimal footprint containers without dependencies. Time for some panna cotta or another desert of your choice to celebrate your success!


Common pitfalls

stat /bin/sh: no such file or directory

When running your container, you get like the following error message

$ docker run -ti --rm feldspaten.org/prog
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown.

Probably you didn’t enclosed the Entrypoint with brackets:

# WRONG
ENTRYPOINT "/app/awesome-prog"

# Right
ENTRYPOINT ["/app/awesome-prog"]

The reason for the failure is that the container tries to execute the entrypoint without brackets in a /bin/sh shell. However this does not exists in our minimal container, so it fails.