DEV Community

Scott Coulton
Scott Coulton

Posted on • Updated on • Originally published at Medium

I cho, cho, choose you container image Part 1.

When I first started my journey into using Docker and Kubernetes, one of the issues I hit was “what base image do I use for my applications?” There are so many options out there. For example, I love Debian, that is what I run on my laptop so do I chose Debian because its what I know? That seems pretty straight forward to make that decision but like with everything in life with the choices we make there are repercussions. As a developer, you want to be armed with the best knowledge to why you made the base image choice. Not only for your applications performance or deployment image size but also things like security. 

I am going to break down our applications into two different groups compiled languages like Go or Rust. The other dynamic languages like Python, Ruby or node.js. In this series posts, I am going to use two examples a Go app in part 2 and a Python app in part 3.

But let's look at the options we have for a base image first. We have four choices a full OS image like Debian, there are also slim versions of full OS’s, next is alpine and last but not least scratch.

So in the post, I will not call out anyone OS vendor as being better or worse as it is a personal choice. So we will class Full OS’s, Slim OS’s, Alpine and scratch as individual groups. 

Let’s start with full Os’s they are the easiest to get started with and most likely the easiest way to get your application up and running as they contain the most packages installed by default. In part 1 of the series, we are just going to compare the images and not worry about the application just yet. One thing that stands out straight away in the full OS’s images is they ship with vulnerable packages out of the box. Now, these are might not be show stoppers for you, you might have risk mitigation in place to use these images. The information about the state of an image is freely available on DockerHub under the tag information. Below is an example.

As you can see there are quite a few critical vulnerabilities that are being deployed before you even add your code. Now let’s move onto our slim images. As it stands now only Debian has a slim image, but what is a slim image? It is a cut down version of the full image with just the base packages it expects that you install any packages you need for your application. By using a slim image you can save about 50% on your image size, for example, the full OS image would be around 100mb and slim is about 54mb.

As you can see from your image security scan we have cut down the vulnerable packages. Unfortunately, there are still two critical packages. Next, we will move on to Alpine Linux. This OS was built from the ground up to be a container native OS. The main change in this OS to a traditional OS image (fat or slim) is Alpine does not use glibc instead it uses musl libc. This is important to know if your application depends on glibc. Alpine Linux by default comes with only the base packages anything your application needs you will have to install. On the upside, the Alpine is just under 6mb for the image.

As you can see from our vulnerability scan there are no critical vulnerabilities in this image. Alpine can be a little tricky to get used to at first as it has its own package manager that you need to learn. If you persist with it I think the benefits will be worth your time. Lastly, we will look at scratch. What is scratch? Scratch is the starting point for all container images. Using the scratch “image” signals to the build process that you want the next command in the Dockerfile to be the first filesystem layer in your image. So there is no package managers or packages. It's just an empty layered file system. You can pull scratch as it is a reserved namespace. Nor will there be any vulnerable packages as there are no packages by default.

FROM scratch
ADD rootfs.tar.xz /
CMD ["bash"]

Above is an example of a full OS images Dockerfile as you can they all start from scratch.

In the next post in this series we will take the learnings from this post and apply them to a real application written in GO.

If you would like to learn more about containers or Kubernetes head to my GitHub page for an open-sourced workshop.

Top comments (0)