27 July 2018
In this post, I’ll show you how to containerize a Python application that uses Slycot and the Python Control library. Installing Slycot is tricky because you’ll need a FORTRAN compiler and a bunch of other dependencies, which isn’t included in most off-the-shelf Docker images like alpine-python.
Docker containers are built from base images. A base image can be an operating system image like Ubuntu, Debian or CentOS. We can have intermediate images called layers on top of our base image. Every line of instruction in our Dockerfile creates a new layer. These layers make up the final Docker container.
Here’s a visual of what it looks like:
Diagram from the Docker Blog.
One common challenge with Docker containers is keeping the image size small. An Ubuntu base image can be over 600MB. This can easily balloon to over 1-2GB once we start installing more layers.
It would be a good practice to start with a minimal base image like Alpine and just add the packages we need.
Here’s the Dockerfile, we’ll start with a Python 3.6 image, and add the dependencies needed by Slycot, numpy and scipy:
FROM python:3.6-alpine RUN apk --update add git openssh && \ rm -rf /var/lib/apt/lists/* && \ rm /var/cache/apk/* RUN apk --no-cache --update-cache add \ gcc \ gfortran \ g++ \ build-base \ wget \ freetype-dev \ libpng-dev \ openblas-dev RUN ln -s /usr/include/locale.h /usr/include/xlocale.h
To prevent Docker from unnecessarily rebuilding pip packages, we’ll use this little trick of adding
requirements.txt to our app directory before doing
ADD requirements.txt /app/ WORKDIR /app RUN pip install --no-cache-dir \ numpy \ slycot \ scipy \ git+https://github.com/python-control/python-control
Side note: I was having some trouble installing the control library properly using
pip install control, that’s why I’m using the Github link. When I tried the pip package in December 2017, it had some compatibility issues with the latest version of Scipy. The issue seems to be fixed in the latest control 0.8.0 version (as of July 2018).
If your app has any addition requirements you can put it in
requirements.txt. Here’s the last part of the Dockerfile:
RUN pip install -r requirements.txt ADD . /app ENTRYPOINT ["python"] CMD ["app.py"]
Alternatively, use Docker pull:
docker pull csianglim/alpine-slycot-control
then run it:
docker run csianglim/alpine-slycot-control
FYI Slycot seems to be really fussy about its dependencies, especially numpy versions. I tried using abn/scipy-docker-alpine as my base image to avoid compiling numpy, scipy and speed up my Docker builds, but Slycot didn’t like it. So if you’re having trouble, try the latest numpy and scipy version.
control library requires scipy and numpy, which are big dependencies, making the final Docker image over 700MB. However, it’s very likely we could optimize the Dockerfile further and shrink the container size. A follow-up article will be posted when I figure that out.