Switching from Ubuntu Based to Alpine Linux Based Docker Image

By | February 13, 2016
Reading Time: 2 minutes

Some time ago I red about the Iron.io and how they created very small Docker images for different languages, such as Python, Java etc. Some days ago I was looking into how to make my Elastalert Docker image smaller, mostly as a therapeutic task, when I recalled the Iron.io Docker images. A quick search revealed that they indeed had a Python image.
My Elastalert Docker image was originally based on the Ubuntu 15.04 Docker image. The following are the changes I had to make to the Dockerfile and related files in order to be able to create a Docker image for Elastalert based on Alpine Linux.

Dockerfile

These are changes made to the Dockerfile:

  • Change the Docker base image to iron/python:2
    As of writing this article, this base image is not based on the latest Alpine Linux version. However, it does come with the Alpine Linux setup scripts installed, which makes it easier to, for instance, set a timezone for a Docker container.
  • Change the package installer command from apt-get to apk.
  • Install the musl library development headers in the package musl-dev.
    This was needed since Elastalert is actually built when the Docker image is created.
  • Install timezone data contained in the package tzdata.
    This data was not present in the base image used.
  • Install openntpd instead of ntp for time synchronization.
  • Create the directory /var/empty that is required for openntpd to function correctly.
    I have seen other base images based on Alpine Linux that does contain this directory, so use the following command to create the directory which will not fail if the directory is already present:
    mkdir -p /var/empty
  • Explicitly delete locally cached packages using the rm -rf /var/cache/apk/* command.
    In Alpine Linux 3.3 and later the flag –no-cache can be used with the apk command to avoid local caching and thus the need to delete the cache.

Start Script

These areĀ  the changes made to the start script:

  • Setting the timezone using the setup-timezone script with the -z flag to take the timezone as a parameter, instead if interactively asking for it in the console.
    On other base images based on more recent versions of Alpine Linux, the setup-scripts have not been installed and there you will have to use this approach to set the timezone instead.
  • Use the command ntpd -s to synchronize the time in a Docker container.
    With Ubuntu I never had to take special actions in order for time synchronization to work. With Alpine Linux however, a Docker container must be run with the SYS_TIME and SYS_NICE capabilities in order for the ntpd command to work properly.
    Partial example: docker run –cap-add=SYS_TIME –cap-add=SYS_NICE …

Size Matters?

With all the above modifications in place, I were finally able to create and run a Docker image with Elastalert, based on Alpine Linux.
What about the size of the image then?
Locally (when building the Docker image on my own computer) the size went from about 377MB to about 190MB, on Docker Hub the size went from about 158MB to 63MB. All this despite the fact that I have not optimized the Dockerfile as much as possible.
In the end I am very pleased with the result and will definitely use Alpine Linux to a larger extent as a base for my Docker images.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *