Docker Config
Part 1, Chapter 4
Let's containerize the FastAPI app.
Start by ensuring that you have Docker and Docker Compose:
$ docker -v
Docker version 24.0.7, build afdd53b
$ docker-compose -v
Docker Compose version v2.23.3-desktop.2
Make sure to install or upgrade them if necessary.
Add a Dockerfile to the "project" directory, making sure to review the code comments:
# pull official base image
FROM python:3.12.1-slim-bookworm
# set working directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install python dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# add app
COPY . .
Here, we started with a slim-bookworm-based Docker image for Python 3.12.1. We then set a working directory along with two environment variables:
PYTHONDONTWRITEBYTECODE
: Prevents Python from writing pyc files to disc (equivalent topython -B
option)PYTHONUNBUFFERED
: Prevents Python from buffering stdout and stderr (equivalent topython -u
option)
We then installed the dependencies and copied over the app.
Depending on your environment, you may need to add
RUN mkdir -p /usr/src/app
just before you set the working directory:# set working directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app
Add a .dockerignore file to the "project" directory as well:
env
.dockerignore
Dockerfile
Dockerfile.prod
Like the .gitignore file, the .dockerignore file lets you exclude specific files and folders from being copied over to the image.
Review Docker Best Practices for Python Developers for more on structuring Dockerfiles as well as some best practices for configuring Docker for Python-based development.
Then add a docker-compose.yml file to the project root:
version: '3.8'
services:
web:
build: ./project
command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000
volumes:
- ./project:/usr/src/app
ports:
- 8004:8000
environment:
- ENVIRONMENT=dev
- TESTING=0
This config will create a service called web
from the Dockerfile.
So, when the container spins up, Uvicorn will run with the following settings:
reload
enables auto reload so the server will restart after changes are made to the code base.workers 1
provides a single worker process.host 0.0.0.0
defines the address to host the server on.port 8000
defines the port to host the server on.
The volume
is used to mount the code into the container. This is a must for a development environment in order to update the container whenever a change to the source code is made. Without this, you would have to re-build the image each time you make a change to the code.
Take note of the Docker compose file version used -- 3.8
. Keep in mind that this version does not directly relate back to the version of Docker Compose installed; it simply specifies the file format that you want to use.
Build the image:
$ docker-compose build
This will take a few minutes the first time. Subsequent builds will be much faster since Docker caches the results. If you'd like to learn more about Docker caching, review the Order Dockerfile Commands Appropriately section.
Once the build is done, fire up the container in detached mode:
$ docker-compose up -d
Navigate to http://localhost:8004/ping. Make sure you see the same JSON response as before:
{
"ping": "pong!",
"environment": "dev",
"testing": false
}
If you run into problems with the volume mounting correctly, you may want to remove it altogether by deleting the volume config from the Docker Compose file. You can still go through the course without it; you'll just have to re-build the image after you make changes to the source code.
Windows Users: Having problems getting the volume to work properly? Review the following resources:
You also may need to add
COMPOSE_CONVERT_WINDOWS_PATHS=1
to theenvironment
portion of your Docker Compose file. Review Declare default environment variables in file for more info.
You should now have:
├── .gitignore
├── docker-compose.yml
└── project
├── .dockerignore
├── Dockerfile
├── app
│ ├── __init__.py
│ ├── config.py
│ └── main.py
└── requirements.txt
✓ Mark as Completed