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.