Using Rocker to build minimal Python Docker images

Oct 20, 2015  

Rocker is a tool developed by Grammarly that is offering additional functionalities to build Docker images.

The syntax of the Rockerfiles is a superset of Dockerfiles.

Rocker is useful for creating minimal Docker images as you can split the process in 2 steps, the first to build your project in a first container and the second to ship and run. In the following part of this post we will further explain and show how we can use Rocker to easily generate Docker images for Python projects.

In the first container, we will install all the tools to generate the Python wheels like a C compiler and all the development headers and libraries. The second container will only hold the installed wheels and dynamic libraries.

First step: The build requirements

If you are already familiar with Dockerfiles, then moving to Rockerfile is really straightforward. The first step is to create a file named Dockerfile at the root of your project.

You can see the full repository here.

FROM python:2.7-slim

The begining of each step is defined by the FROM lines.

ADD . /src
WORKDIR /src

This is pretty standard Dockerfile syntax where we copy the sources of the project into a subfolder of the image.

RUN apt-get update && apt-get install -y \
    build-essential

We install the build-essential package to be able to build Python packages having C dependencies.

REQUIRE ["Version"]
RUN sed -ie s/\'0.0\'/\'{{ .Version }}\'/g setup.py

Rocker provides a templating functionality that we use to set the version number of our package. This can be really useful if you use a CI and want to use the build number as the version number.

Here is an excerpt of our setup.py

setup(
    name='rockerdemo',
    version='0.0',
    ...
)

To pass the value of Version you will use the -var parameter

$ rocker build -var Version=1.0

Rocker provides the -print parameter to visualize the Rockerfile after it has been templated.

RUN python setup.py bdist_wheel
RUN pip wheel .
RUN pip wheel setproctitle gunicorn json-logging-py

We build all the wheels that we will need: our main app, its dependencies and the dependencies that we will need to actually run the container like gunicorn.

EXPORT /src/wheelhouse

All the wheels are stored in /src/wheelhouse, so we EXPORT this folder to be able to IMPORT it in the next step.

Second step: The container that we will ship and run

FROM python:2.7-slim

IMPORT /wheelhouse

RUN pip install --no-index --find-links=file:///wheelhouse rockerdemo setproctitle gunicorn json-logging-py

RUN rm -rf /wheelhouse

We IMPORT the wheels, install them and remove the /wheelhouse folder.

COPY docker/logging.conf /logging.conf

COPY docker/gunicorn.conf /gunicorn.conf

EXPOSE 8000

ENTRYPOINT ["/usr/local/bin/gunicorn", '--name", "rockerdemo", "--config", "/gunicorn.conf", "--log-config", "/loggin\
g.conf", "-b", ":8000", "rockerdemo:app"]

This part is pretty standard Dockerfile syntax.

Building, tagging and pushing the container

PUSH sebest/rocker-with-python-project:{{ .Version }}
PUSH sebest/rocker-with-python-project:latest

This part will tag the build and optionaly push it to the Docker registry if you use the -push parameter

The final step is to actually build the image and push it:

$ rocker build -var Version=1.2 -push