At DueDil we have a number of microservices that complement our web platform and API, many of which are written in Python. We use Docker to build and run these services, which makes it simple to get them running locally for development.
Working on one of these services, a simple bottle server which retrieves and presents data from a third party API, I noticed that the time it took to build the image was painfully slow, clocking in at around 8 minutes.
I decided to investigate this and see if I could speed things up. Opening the dockerfile, the first thing I noticed was that the image was using a custom base image, based off the official Ubuntu image. This 1.7Gb image included the entirety of Ubuntu as well as loads of tools - git, curl, build-essential etc, useful for general development, but overkill for a small python service.
I decided instead to base it on Alpine, a tiny linux distribution, with a base image size of around 5mb. The official Python docker repository includes an image with Python installed, based off of Alpine, which comes in at around 60mb. After adding a few system libraries that the service needed, the build time was now coming in at around 4 minutes. Not bad, but I felt we could still do better than that!
While watching the build process, I noticed that the part that took the longest was installing the python dependencies with pip. pip installs are usually pretty fast, in part because of the use of Python "Wheels", pre-built, packaged distributions of the libraries that are being installed. However in my case I could see all of the dependencies were being downloaded as source and compiled then and there, because there are no pre-built wheels for the Alpine distro.
Alpine uses a package manager much like apt-get or brew, called apk. Checking out the package list for apk here, I noticed that a lot of python libraries were available as pre-built Alpine packages. I used these where I could, moving the dependencies from the setup file to the dockerfile and installing them with apk. Versioning is even available in apk with the syntax listed here.
After these changes, the build time was reduced to around 55 seconds!
There are a few downsides to this method, chief of which is that the requirements are now listed in an unorthodox place, but good documentation should point this out to any future developers working on this service, and I think its worth it for the time saved and distractions avoided while waiting for the build!
Interested in working with Docker and solving similar problems? Come work with us, we're hiring!