Tutorial, Python, Docker, Development

Converting Python Applications into Docker Images

When you hear people talk about containers, you'll generally hear 'Docker' thrown around, too.

In this tutorial, I'm going to show you how easy it is to convert existing Python applications into Docker images, so that you can get up and running quickly.

For a while, I was splitting my Python applications for T.I.T.U.S. across multiple AWS EC2 instances, because I guess I thought they would need to consume more resources than they actually did, and I wanted to make sure no component was bogged down.

Not only was this overkill from a processing standpoint, but it was starting to get expensive to run, too (not to mention that keeping multiple server instances up-to-date is a big headache in and of itself - especially for a personal project)!

ENTER DOCKER

I started messing around with Docker where I'm currently employed, and I quickly realized how easy and unscary (legit word? it is now) it was to get up and running. I then thought of the potential Docker had for my own personal projects, and I figured that I could not only convert all of my existing applications to Docker images, but I could consolidate all of my servers into one! On top of that, I could ditch EC2 altogether, and just run Docker containers on an old Ubuntu rack server collecting dust in my basement! Hells to the yeah!

After doing just a smidge of research, I came across the official Python repository on Docker Hub, and I saw they had multiple images created that were already configured to run various flavors of Python.

Reading through the documentation in the Python repository, I saw that it was dead simple to convert my existing Python applications into Docker images. All I had to do was add a Dockerfile to my projects, which contained only six lines of commands, tell Docker to build the images, push the images to my own Docker Hub account, and then pull them down and run them as containers on my server.

Bingo bango, easy peasy.

THE DOCKERFILE ... FILE

The first thing you need to do is to add a file in the root directory for your Python project called 'Dockerfile'. That's right, no file extension, just the name, 'Dockerfile'. If you're on Windows, you probably won't be able to just right-click in Windows Explorer and create a new text file with this name, as Windows requires you to add a file extension.

Instead, you'll need to open up a text editor (Notepad++ should work) or use your favorite IDE to create the file.

Once that's created, here are the six lines that need to be in your Dockerfile (why on earth would you include "file" in a file name? err ... never mind) file, taken straight from the Python repository docs:

FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python", "./your-daemon-or-script.py" ]

All right, now let's break this down.

When you go to run the 'docker build' command later, the first line in this file tells Docker to use the 'python:3' image as a base image. Essentially, you're saying that you want to build your new Docker image on top of the 'python:3' image, as it already has Python 3 configured and ready to go.

The next line tells Docker which directory to use as the working directory, so all of the files will be copied into this location in a Docker container when you fire one up later.

Next up is a 'COPY' command that copies a file called 'requirements.txt' from the same root directory where you created the Dockerfile ... file, and places it into the working directory. Of course, you'll need to create this file if you haven't already done so. What this file contains is a listing of all of the packages your application requires to run.

You can either manually type out all of the packages you need, or you can utilize the 'pip freeze' command, which can dump a listing of the packages currently installed on your machine (or virtual environment) into a file called 'requirements.txt'.

The 'RUN' command (line 6 above, if you include the blank lines) will execute pip and install all of the packages listed in the 'requirements.txt' file in your Docker container.

After the packages are installed, the 'COPY' command on line 8 will copy of the files in your project directory over to the working directory listed on line 3.

The final command that is run, then, is 'CMD', which tells Docker to run the command listed as the first argument in the square brackets that follow. The second argument is actually an argument that is sent to the 'python' command, which tells Python which script file to run when the container starts.

I generally call my starting script file, 'run.py', so for me, line 10 looks like this:

CMD [ "python", "./run.py" ]

WRAPPING UP

Now, your application is ready to be packaged up as a Docker image and run as a container, either locally or on a remote box.

From here, you can follow the remaining instructions on the Python repository Docker Hub page to build the image and run a container that houses your application.

I would also encourage you to look into adding a '.dockerignore' file alongside your 'Dockerfile' file to exclude files/directories that you don't want included in your new Docker image (e.g. virtual environment directories if you use virtualenv, Git directories/files, IDE config files, etc).

And as always, with your new nugget of knowledge, go out and create some awesome shit!

Author image

About Tony Thorsen

Father of two, husband of one, Maker of many things. Tinkerer, dreamer, pixel nudger.