2 October 2018

docker parent image

by mo

In this article I intend to go over the different choices for a docker parent image. Choosing a good parent image for your service can be a difficult decision. The factors that I am going to consider are:

  • Convenience
  • Security
  • Size

As a complement to this article I recommend reading:

The images that I will evaulate are:

  • centos
  • alpine


To me convenience implies having the ability to run your software easily on the base image with little to zero hacks in order to run. For example if my service depends on the imagemagick library, adding this package to the image should be simple.

When building an image for a ruby service it would make sense to have a minimal ruby installation on the image. If additional steps are needed to install the necessary software then this decreases the convenience factor. If less effort is needed than this increases the convenience factor.

Let’s take a look at the centos base image.

も docker run -it centos:7 /bin/bash
Unable to find image 'centos:7' locally
7: Pulling from library/centos
Status: Downloaded newer image for centos:7
[root@16351ffd32af /]# ls /
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt
proc  root  run  sbin  srv  sys  tmp  usr  var

[root@16351ffd32af /]# ruby -v
bash: ruby: command not found

[root@16351ffd32af /]# yum install ruby -y
[root@16351ffd32af /]# ruby -v
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]

Install ruby in CentOS is pretty easy. However, the current version of ruby in the default repos offers an out of date ruby that is no longer officially supported. This means if you want to use a supported ruby you will need to find other ways to install it yourself. In most cases, this means adding your own custom rpm repo’s and pulling the ruby from there.


Let’s take a look at Alpine linux.

も docker run -it alpine:latest /bin/sh
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
4fe2ade4980c: Pull complete
Status: Downloaded newer image for alpine:latest

/ #
/ # apk add ruby
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
(1/9) Installing ca-certificates (20171114-r3)
(2/9) Installing gmp (6.1.2-r1)
(3/9) Installing ncurses-terminfo-base (6.1_p20180818-r1)
(4/9) Installing ncurses-terminfo (6.1_p20180818-r1)
(5/9) Installing ncurses-libs (6.1_p20180818-r1)
(6/9) Installing readline (7.0.003-r0)
(7/9) Installing yaml (0.1.7-r0)
(8/9) Installing ruby-libs (2.5.1-r2)
(9/9) Installing ruby (2.5.1-r2)
Executing busybox-1.28.4-r1.trigger
Executing ca-certificates-20171114-r3.trigger
OK: 25 MiB in 22 packages
/ # ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-musl]

With very little effort a modern ruby was installed and available to an alpine image. CentOS makes it easy to install an unsupported version of ruby. Alpine makes it easy to install a modern supported version of ruby.

Alpine is the winner for convenience.


Centos 7

sudo docker images | grep centos
centos                                                   7      5182e96772bf        8 weeks ago         200MB
centos                                                   latest 5182e96772bf        8 weeks ago         200MB

The vanilla centos:7 image is 200MB.


も docker images | grep alpine
alpine                                                   latest 196d12cf6ab1        2 weeks ago         4.41MB

The alpine image starts at 4.41MB. The CentOS image is 200 times larger than the alpine image.

Alpine is the winner in size.


The Alpine linux about page says:

Alpine Linux was designed with security in mind. The kernel is patched with an unofficial port of grsecurity/PaX, and all userland binaries are compiled as Position Independent Executables (PIE) with stack smashing protection. These proactive security features prevent exploitation of entire classes of zero-day and other vulnerabilities.

The minimal size of Alpine linux gives a smaller footprint to attack. However, flaws have been discovered in the alpine package manager.

Flaws will be found in any distribution but with less packages installed by default this decreases the attack surface for vulnerabilities that can lead to exploits.

Alpine uses musl libc instead of GNU libc. This can sometimes pose problems because musl libc doesn’t always exhibit the same behaviour as GNU libc and can lead to issues down the road. (Example: https://www.elastic.co/blog/docker-base-centos7)


Ships with GNU libc that is pretty well trusted and dependable. CentOS is the Community Enterprise OS which is the binary compatible version of RHEL. This means all security updates released by RHEL are picked up by CentOS. This allows for a larger community to respond and resolve security issues.

In terms of security, this one is difficult for me to judge. Alpine is a smaller distro but also has a smaller community that supports it. It uses a different libc that isn’t as hardened as GNU libc. In terms of security, I think CentOS is the winner due to it’s larger community and patches provided by RedHat.

In conclusion, I think CentOS is probably the safer choice. Alpine will likely work for most teams shipping services that don’t depend heavily on libc. Depending on how large your software is the final image may or may not be that different even if you start with the smaller Alpine image.

For the time being I will continue to use alpine for personal projects and wont push back to hard if we’re required to use CentOS at work.