How To Build Your Own Docker Images

Build Your Own Docker Images

Thanks to Ugur Ceylan for the base image! CC BY 2.0

What’s with the Docker community’s love affair with Alpine Linux? Tiny containers means more compute resources left over for actual… computing! Alpine Linux is particularly tiny. It says so, right on the tin: “Alpine Linux is a security-oriented, lightweight Linux distribution based.”

Do you like saving money? I like saving money. Better resource utilization means happy bank accounts.

Let’s take a closer look at Alpine Linux on Docker. Heck, while we’re at it let’s build our own image.

Building Your Own Container

The first step to building an image is creating a new directory, and opening the Dockerfile. Follow along, but replace the “atom” line with your favorite text editor.

cd ~
mkdir buildingDockers
cd buildingDockers
atom Dockerfile

In atom, add the following line to the file and save:

FROM iron/base

This is’s base image for containers, but you could actually name any image you want from the Docker repo.

I like the iron/base image, because (newsflash!) this is an blog. But, also since it adds essential libraries that come in handy when we start adding and building other packages.

All we need for starters is the FROM command. Let’s build the container! On the command line type:

docker build -t namehere .

Hero in a Half Shell

Great, we’ve got a container. Now what do we do with it?

Accessing the shell is a great way to admire our work. It’s also pretty handy for troubleshooting. To fire up the image and drop to the shell, try:

docker run --rm -it namehere /bin/sh

Note, this is NOT Bash.

There are a bunch of useful commands for building Docker images. To simplify, this guide is just going to cover FROM (noted above) and RUN commands. Once you build up some comfort, it’s definitely worth visiting the official docs to look at the whole list of options.

Born to RUN

RUN is how to execute a command. For instance, Alpine Linux has a nice package repository, similar to apt-get (and the like). To see what’s installed already, try adding the following to your Dockerfile:

RUN apk info

Admiring our installed packages is only so useful. Let’s add something. To do so, pick a package from the Alpine Linux packages repo. Now, add it to the Dockerfile:

RUN apk add packageNameHere

Best Practices and Caveats

Docker hosts a great best practices guide. In it, they note the importance of keeping images small in size. Avoiding bloat is simple and intuitive. No sweat, right? Just install the software that’s needed.

Wait, crap. Are you also limiting the amount of RUN commands in your Dockerfile? Dockerfiles are built in layers. Each command adds a new layer. More layers means more work has to be done to cleanly merge them all together.

Dress in Layers

To reduce layering, it’s recommended to group commands. This will add a single layer while performing as much work as we desire. Grouping commands looks something like:

RUN command1 && command2

Make it more readable by using “” and carriage returns:

RUN command1 
  && command2 
  && command3

Grouping commands is great until it turns into mental gymnastics. When that happens, prioritize maintainability. Use an extra RUN command if it reduces the cognitive load. As Kelsey Hightower notes in 12 Fractured Apps, twisting a RUN command into a shell script is a less than great (read: terrible) way to keep an image maintainable.

Drop the Cache, and Nobody Gets Hurt

There’s no need to cache package installs in Docker-land. So, let’s drop the cache. To do so add the following near the end of your Dockerfile:

RUN rm -rf /var/cache/apk/*

Musl Milk

If you venture outside of the official Alpine Linux apk ecosystem, there’s a good chance you’ve chosen to compile from source. Be aware that Alpine Linux relies on Musl rather than GCC.

Compile accordingly.

Busy Beat Boxin’

Alpine Linux made a few sacrifices at the shrine of distro size. Rather than install the standard suite of *Nix utilities, they opted for BusyBox. It’s a nice (tiny) compaction of some common utilities.

That means that some utilities might not accept the usual GNU flags. It also means some utilities are completely missing. Want curl in your image? You’ll have to install it.

Keep Learning

Alpine Linux has a great wiki if you find yourself looking for more handy tips.

Lastly, it’s easy to inspect the Docker images that power our handy IronWorker guides. If you’d like to see how we write our Dockerfiles, visit