Skip to content

Commit 1397703

Browse files
committed
blog post
1 parent 7cc7631 commit 1397703

File tree

7 files changed

+130
-4
lines changed

7 files changed

+130
-4
lines changed

_config.yml

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ theme: minima
2727
plugins:
2828
- jekyll-feed
2929

30+
include: ["_posts"]
31+
32+
defaults:
33+
- scope:
34+
path: "assets/images"
35+
values:
36+
image: true
37+
3038
# Exclude from processing.
3139
# The following items will not be processed, by default. Create a custom list
3240
# to override the default setting.

_layouts/blog.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
layout: default
3+
---
4+
5+
<div class="row">
6+
<div class="twelve columns" style="margin-top: 1%">
7+
<p class="blog-header-date">{{ page.date | date_to_long_string}}</p>
8+
<h1><b>{{ page.title }}</b></h1>
9+
<br>
10+
{{ content }}
11+
</div>
12+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
layout: blog
3+
title: "Dockerfile, Slycot and Control"
4+
date: "2018-07-27"
5+
author: ["Siang Lim"]
6+
---
7+
8+
# Containerizing Slycot and the Python Control Systems Library
9+
In this post, I'll show you how to containerize a Python application that uses Slycot and the [Python Control](https://github.com/python-control/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](https://github.com/jfloff/alpine-python).
10+
11+
# Docker introduction
12+
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.
13+
14+
Here's a visual of what it looks like:
15+
16+
![docker diagram]({{ "/assets/images/container_layers.png" | absolute_url }}){:class="center-image"}
17+
18+
*Diagram from the [Docker Blog](https://blog.docker.com/2015/10/docker-basics-webinar-qa/).*
19+
20+
# Creating a Dockerfile
21+
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.
22+
23+
It would be a good practice to start with a minimal base image like [Alpine](https://github.com/gliderlabs/docker-alpine) and just add the packages we need.
24+
25+
Here's the Dockerfile, we'll start with a Python 3.6 image, and add the dependencies needed by Slycot, numpy and scipy:
26+
27+
```
28+
FROM python:3.6-alpine
29+
30+
RUN apk --update add git openssh && \
31+
rm -rf /var/lib/apt/lists/* && \
32+
rm /var/cache/apk/*
33+
34+
RUN apk --no-cache --update-cache add \
35+
gcc \
36+
gfortran \
37+
g++ \
38+
build-base \
39+
wget \
40+
freetype-dev \
41+
libpng-dev \
42+
openblas-dev
43+
44+
RUN ln -s /usr/include/locale.h /usr/include/xlocale.h
45+
```
46+
47+
To prevent Docker from unnecessarily rebuilding pip packages, we'll use this little [trick](https://www.aptible.com/documentation/enclave/tutorials/faq/dockerfile-caching/pip-dockerfile-caching.html) of adding `requirements.txt` to our app directory before doing `pip install`:
48+
49+
```
50+
ADD requirements.txt /app/
51+
WORKDIR /app
52+
53+
RUN pip install --no-cache-dir \
54+
numpy \
55+
slycot \
56+
scipy \
57+
git+https://github.com/python-control/python-control
58+
```
59+
60+
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](https://github.com/python-control/python-control/pull/170) with the latest version of Scipy. The issue seems to be fixed in the latest control 0.8.0 version (as of July 2018).
61+
62+
If your app has any addition requirements you can put it in `requirements.txt`. Here's the last part of the Dockerfile:
63+
64+
```
65+
RUN pip install -r requirements.txt
66+
ADD . /app
67+
68+
ENTRYPOINT ["python"]
69+
CMD ["app.py"]
70+
```
71+
72+
# Docker Hub
73+
This Docker container is also available in this [GitHub repo](https://github.com/csianglim/alpine-slycot-control).
74+
75+
Alternatively, use Docker pull:
76+
77+
```
78+
docker pull csianglim/alpine-slycot-control
79+
```
80+
81+
then run it:
82+
83+
```
84+
docker run csianglim/alpine-slycot-control
85+
```
86+
87+
88+
89+
90+
# Other known issues
91+
FYI Slycot seems to be really fussy about its dependencies, especially numpy versions. I tried using [abn/scipy-docker-alpine](https://github.com/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.
92+
93+
# Conclusion
94+
The `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.

assets/css/style.css

+12
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,15 @@ h2{
6565
margin-bottom: 20px;
6666
}
6767

68+
.blog-header-date{
69+
margin-bottom: 0;
70+
font-size: 0.9em;
71+
color: #ccc;
72+
}
73+
74+
.center-image
75+
{
76+
margin: 0 auto;
77+
display: block;
78+
}
79+

assets/images/container_layers.png

16.9 KB
Loading

blog.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ permalink: /blog/
66

77
#### Blog
88

9-
Coming soon.
10-
119
<div class="blog-posts">
1210
<ul>
1311
{% for post in site.posts %}
1412
<li>
15-
<a class="post-title" href="{{ post.url }}">{{ post.title }}</a>
13+
<b><a class="post-title" href="{{ post.url }}">{{ post.title }}</a></b>
1614
<p class="post-date">{{ post.date | date_to_long_string}}</p>
1715
</li>
1816
{% endfor %}

cv.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ permalink: /cv/
66

77
#### CV
88

9-
CV available at [https://csianglim.github.io/markdown-cv](https://csianglim.github.io/markdown-cv).
9+
CV available [here](https://csianglim.github.io/markdown-cv).
10+
11+
Source available on [GitHub](https://github.com/csianglim/markdown-cv/blob/gh-pages/index.md), based on the [markdown-cv](https://github.com/elipapa/markdown-cv) template.

0 commit comments

Comments
 (0)