Choosing a Base Image For Your Dockerfile
How to choose a base image for your Dockerfile? I have written about my process of creating a Dockerfile before, and this detail seemed to warrant an own closer look.
Here’s how I would go about the decision in detail.
What’s The Usecase?
What do I need this image to do for me? Do I need to build a new one?
If there’s a ready-made official image available, I would opt towards using it instead of rolling my own. Except, if there are good reasons to do so.
Need a PostgreSQL image? Docker Hub got you covered. This way you can skip the base image decision here, and get back to things which will benefit you more.
Scenario 1: A Convenient Place To Tinker
Go with a mainstream, generic distribution you know well. For me, this is the latest LTS version of Ubuntu. I know I’ll be able to install any packages I need, and figure out issues if they arise.
For others the right answer may be Fedora, CentOS or Debian. Whatever you feel most familiar with.
Scenario 2: Made For Your Language Choice
This is especially useful for environment of dynamic languages - like Python or NodeJS.
Instead of getting started from a clean slate, and having to figure out how to install the $LANGUAGE version you need, you can use well-thought-out base images for the environment you need.
Take a look at the node or Python base images on Docker Hub.
You’ll see they offer different versions, but also different flavours for each! You can go with alpine, different versions of Debian (stretch, buster) and their slim variants among others.
Personally, I would not use Alpine with Python - musl can lead to new, exciting buts as glibc is more prominent in the Python ecosystem.
Usually, the slim debian versions are the ones I would prefer in this case, to get a tradeoff between stability, image size and familiarity.
Scenario 3: You Don’t Need Much At All
Care to keep it minimal? This is the case if you want to package up a self-contained binary. For example, if you’re building a Go application which does not need any external dependencies to run.
It’s valid to start from “scratch” in this case, pick a small base image of your choice (like alpine) or even busybox.
Jerome Petazzoni published a great article on that topic. I highly recommend the complete series if you’re in a situation where getting the size small is a high priority for you.
The quesion whether you want a more or less minimal image, apart from size, is the convenience of investigating issues with them. There are ways to debug very minimal images, But that’s a different topic. Personally, I would be tempted to use scratch until the first issue arises…
Scenario 4: You Have More Strict Requirements
As usually, if you’re building something which is supposed to stick around for a while, be reliable and secure you will need to consider your tradeoffs more carefully.
The same points from above apply:
- Are you familiar with the distro?
- Is it well-used for your stack? (This speaks against alpine for Python apps for example.)
- Does it strike the right balance between size and convenience? (The more security requirements, the less convenience you can have.)
Apart from those, we’ll need to consider stability and availability of timely updates.
- Can you reliably pin a version, and be sure that your builds are reproducible?
- Will you get updates for packages you rely on?
One good thing, is when your base image provides regular updates in response to security issues. This way, you can be sure that switching to the most recent version of your base image will help you be up-to-date with security fixes.
If your base image does not receive timely updates (which can be the case with language-centric images), you will have to take extra care to plug those holes yourself.
I hope this article has helped you get a better understanding of base image choice considerations.
In the end, your requirements and preferences should be the main factors going into decision.
If you want to use a slim Debian image for your Go application, you do you!
If you want to use your favorite distribution when tinkering with a dockerized app, there’s no urgent reason to do otherwise.
Just remember, that it’s all about tradeoffs and what’s right for you.