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.
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
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!
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.