Dockerizing an app that uses Pillow is not a good intro to Docker

Genji Tapia
4 min readDec 9, 2020

Learning docker is a very quick to do task. After a few very short tutorials and some templates you’re equipped with enough knowledge to dockerize one of your own apps. This isn’t a how-to blog to dockerize an app. Instead, it’s my journey in dockerizing my first app.

Note: It wasn’t easy at all!

Given that I’ve been developing passion projects in Flask for about a year, I had a variety of apps to choose from to deploy using Docker. I really wanted to dockerize a game that suffered from running too slow on Heroku. But that app required persistent data and setting up a connection with the one-click app MongoDB. “I’ll do something easier,” I said to myself. So I selected an app that also uses Flask for its backend and only needed a couple of other imports.

The singular source of my problems is one of those other imports. Pillow. Pillow is a Pythonic fork of PIL, which is an image processing library which allows you to do a variety of useful image manipulations.

Importing Pillow into a Python app is simple. $pip install Pillow then make sure you have import PIL in your .py file. Yes, even though we install Pillow we import PIL. It’s possible to install PIL, but it’s not the one we want. The issues begin when when building out our Dockerfile. This issue come from the fact that we’re often using a streamlined OS base, so all of the dependencies that are usually available when you perform a $pip install are not available to us in Docker. There is little documentation for the Pillow dependencies, you can find them by digging around the issues on the Pillow GitHub, but thankfully you don’t have to do that work. StackOverflow is our friend and has streamlined a solution to the issue.

RUN apk update \
&& apk add — virtual build-dependencies gcc python3-dev musl-dev \
&& apk add jpeg-dev zlib-dev libjpeg \
&& pip install Pillow \
&& apk del build-dependencies

https://stackoverflow.com/questions/57787424/django-docker-python-unable-to-install-pillow-on-python-alpine

My immediate problem to looking at this code is that I wasn’t using an alpine base. so apk commands were unavailable to me. I was using a python base. Searching for alternative commands brought me to a wiki resource to convert apk commands to apt-get which will get the job done.
https://wiki.onap.org/display/DW/Migrating+Dockerfiles+from+Debian+apt+to+Alpine+apk

The problem with converting the commands is that all of the above dependencies are not available using apt-get. That, and the nice feature to slim your container file size by using a virtual container is not available in a python base. The solution for this was to change my base to an alpine/python hybrid.
FROM library/python:3.7-alpine as base

At last! Installing my other dependencies from the requirements.txt worked without a hitch and the app deployed.

However… when running my application I was once again back to the land-of-programmer problem-solving because of a custom font I had implemented in my app. Pillow threw an error:
ImportError: The _imagingft C module is not installed

Stack Overflow makes some suggestions to fix the error, for a python base
apt-get install libfreetype6-dev

or the alpine base dependencies
apk add — no-cache g++ freetype-dev

But neither option worked for me. Besides, we already have all of our dependencies covered. The issue may be deeper in how Docker’s layers work with the OS to read a ‘.dfont’ file. Instead of digging deeper, I’ve opted into another solution.

# font = custom_font
I disabled my custom font.

It’s not an ideal solution. But I do have a deployed application and have isolated the source of the issue.

Future development gives me a couple options:

However, one of the additional features I want to put into the app would allow the user to scale, rotate, and select their own font. So further understanding of all-the-above will be a necessity.

The overall experience was more then I had anticipated. I did learn far more about Docker in the process, but the struggle was real and nearly had me willing to give up. Therefore I would not recommend it without the additional support the links I’ve provided can give you.

I think though, instead of developing this app futher I’ll take a break a from the project and instead “I’ll do something easier.” Perhaps dockerizing the Flask Game + MongoDB app I had originally thought of.

My original heroku app is available at https://imja.herokuapp.com
The dockerized version is deployed at https://imja.dev.genji.games

--

--