Introduction

Docker containers can be a burden when the image gets too large.

By default, the Golang Docker container at its smallest is 123 MB. While seemingly small, this can result in annoying latency and slowness when deploying new tooling at scale.

In this article I show you how to create small containers that use up to date tools. I'll use the tool waybackurls from tomnomnom as an example.

Traditional Dockerfile Creation

Typically, we would create a Dockerfile that looks like the following for our desired Golang tool.

# This is our base container
FROM golang:1-alpine

# Installing git and waybackurls within the container
RUN apk update && \
    apk add git && \
    go get github.com/tomnomnom/waybackurls

# Setting our entrypoint so we can easily use the new tool
ENTRYPOINT ["waybackurls"]

While this works perfectly, our resulting Docker image is 130 MB. We need to explore other features of Docker to create a smaller container.

Dockerfile as builder

One of the most challenging things about building images is keeping the image size down. Each instruction in the Dockerfile adds a layer to the image, and you need to remember to clean up any artifacts you don’t need before moving on to the next layer.

In Docker version 17.05 and later, we now use the as builder feature in our Dockerfile to keep the image small. This feature is often referred to as multi-stage builds. It allows us to use an intermediary container to build an up to date version of our Golang tool and then move it into a much smaller container.

An example of a multi-stage Dockerfile:

# Using the golang alpine container as an build enviornment
FROM golang:1.13-alpine3.10 as builder

# Adding git and installing our tool from source
RUN apk --no-cache add git
RUN go get github.com/tomnomnom/waybackurls; exit 0
WORKDIR /go/src/github.com/tomnomnom/waybackurls
RUN go install ./...

#Spinning up a new container that is much smaller
FROM alpine:latest
RUN apk --no-cache add ca-certificates

# Moving our previously built tool into the new container
COPY --from=builder /go/bin/waybackurls /bin/waybackurls

The resulting container is now only 13.5 MB in size. That is big improvement!

Conclusion

You'll find that this is extremely useful when creating containers used for every day penetration testing work. Small containers help us scale our operations and continuously engage with new tooling.

References

This feature of Docker has quite a lot more to it that wasn't mentioned here.

Learn more: Docker multi-stage builds

Become a ninja: Advanced multi-stage builds

- Nicholas Anastasi