Containerize a Python Application

Learn how to containerize a Python application.

We begin by creating a simple web application in FastAPI. Then, we use that application to create a Docker image, and finally, we launch a container from that image.

FastAPI is a modern, fast (high performance) web framework for building APIs with Python 3.6+ based on standard Python-type hints. Though FastAPI is used in this lesson, we can apply what we learn to other Python frameworks, such as Flask, Django, and so on.

The application is a web API that returns a random name. If we haven’t cloned the course’s repository yet, we can clone it by running the following:

git clone https://github.com/abiodunjames/docker-lessons.git

We can find the source code for this lesson in the path-to-docker-lessons/python-fastapi/exercise directory.

Inside the exercise directory, there are two main files:

  • src/main.py: This file contains the application’s endpoint that returns a greeting with a random first and last name.
  • requirement.txt: This contains the application dependencies.

In the next step, we Dockerize this application.

Create a Dockerfile

The first phase in containerizing our application is to create a Dockerfile, which will tell Docker how to build the Docker image.

Create a Dockerfile with the following command:

$ touch Dockerfile

With this Dockerfile, we have three files. The application structure should look like this:

.
├── Dockerfile
├── requirements.txt
└── src
    └── main.py

1 directory, 3 files

In the Dockerfile, we specify the base image from which to start. For a Python application, we need a Python runtime. Therefore, we use FROM python:3.9-slim as the base image:

FROM python:3.9-slim

After this, we set the working directory. We define the working directory as /src using the WORKDIR command:

WORKDIR /src

Since applications are rarely made entirely of one person’s own code, they frequently rely on dependencies and libraries created by others. The application dependencies are defined in requirements.txt in this example.

We copy the requirements.txt file and install the application’s dependencies as follows:

COPY requirements.txt ./

After this, we install additional dependencies as follows:

RUN pip install --upgrade pip && \
    pip install -r requirements.txt

The next step is to copy the source code using the COPY command to the working directory in the image:

COPY . .

The EXPOSE instruction, as discussed in the previous lesson, indicates the port on which the container listens. Therefore, we define the port to expose as 3000:

EXPOSE 3000

It’s always a best practice to run a container process as a non-root user. Therefore, we create a dedicated user with this code:

RUN useradd -M appuser && chmod a+w /src
USER appuser

Now, we define the command to run the container process as below:

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "3000"]

The CMD command tells Docker how to run the application we package in the image.

When we put everything together, the content of the Dockerfile looks like the following:

Get hands-on with 1200+ tech skills courses.