In this tutorial, we will learn how to develop a Python FastAPI application in a Docker container. We will also use docker-compose to orchestrate the containerization of the application.
Prerequisites
Before we start, make sure you have the following installed on your machine:
- Docker
- docker-compose
- Poetry
- Python 3.11.2
Follow this tutorial to install prerequisites.
- Setting up the Project
Let's start by creating a new project directory and navigating to it:
mkdir fastapi-docker
cd fastapi-docker
- Set the virtual env to be created inside the project directory
poetry config virtualenvs.in-project true
- Initialize the project using
poetry
and follow the instructions
poetry init
At the end of this step, you should have a pyproject.toml file that looks like this:
[tool.poetry]
name = "fastapi-docker-tutorial"
version = "0.1.0"
description = ""
authors = ["Your Name <your@email.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11.2"
fastapi = "^0.95.1"
uvicorn = "^0.21.1"
Jinja2 = "^3.1.2"
[tool.poetry.group.dev.dependencies]
black = "^23.3.0"
mypy = "^1.2.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
- Create a directory called
app
mkdir app
cd app
- Create a new file called
app.py
inside theapp
directory. This file will contain the FastAPI application code.
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
- Create a new directory called
templates
in the same directory as yourapp.py
file and add a new file calledindex.html
. Add the following code to the file:
<!DOCTYPE html>
<html>
<head>
<title>FastAPI Docker Tutorial</title>
</head>
<body>
<h1>FastAPI Docker Tutorial</h1>
<p>Welcome to the FastAPI Docker Tutorial!</p>
</body>
</html>
- Install the dependencies for the project:
poetry install
This will install all the required dependencies for the project inside a virtual environment managed by Poetry.
- Create the Dockerfile
Now that we have the project set up with its dependencies, create a Dockerfile to containerize the application.
Create a new file called Dockerfile
in the project directory with the following content:
FROM python:3.11.2-buster
ENV DEBIAN_FRONTEND='noninteractive'
RUN apt-get update && apt install -y curl
RUN curl -sSL https://install.python-poetry.org | python
ENV PATH="${PATH}:/root/.local/bin"
RUN poetry config virtualenvs.in-project true
WORKDIR /app
COPY . .
RUN poetry install
EXPOSE 8000
This Dockerfile is based on the official Python 3.11.2 image and installs Poetry inside the container. It also sets the working directory to /app
and copies the project files into the container. Lastly, it installs the project dependencies with Poetry and exposes port 8000, which is the port our FastAPI application will listen on.
- Create the
docker-compose.yml
file
In this step, we will create a docker-compose.yml
file to define and run our container. docker-compose
is a tool that allows us to define and run multi-container Docker applications. We will use it to define our tutorial
service.
Create a new file called docker-compose.yml
in the project directory with the following content:
version: "3.8"
services:
tutorial:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- .:/app
- /app/.venv
command:
[
"poetry",
"run",
"uvicorn",
"--host",
"0.0.0.0",
"--port",
"8000",
"app.app:app",
"--reload",
]
This docker-compose.yml
file defines a service called tutorial
. It uses the build
keyword to specify that the Dockerfile for this service is located in the current directory (.
) and has a name Dockerfile
. And it will be exposed on port 8000
of the host machine (ports: - "8000:8000"
).
Two volumes are mounted to the container, the current working directory (.
) is mapped to /app
directory in the container, and the .venv
directory located in /app
is mounted to an anonymous volume. This allows us to persist the virtual environment even after the container is deleted, but also allows us to access the project directory from within the container.
We are maintaining the local .venv
because the local .venv is required for VSCode to provide syntax highlighting and code type checking based on the installed packages in the virtual environment. Additionally, if you have type annotations in your code, tools like mypy can use the virtual environment to perform static type checking. So maintaining the local .venv in sync with the container's virtual environment allows for better development experience and code quality.
The command
section specifies the command to be run when the container starts. Here, we are using Poetry to run the uvicorn
server, which is the ASGI server that we will use to serve our FastAPI app. We specify the host and port number for the server, as well as the module and app that should be run. The --reload
option enables live reloading of the server, so that any changes made to the code will automatically restart the server.
- Start the container
With the Dockerfile and docker-compose.yml
file in place, we can start our container using the following command:
docker-compose up --build
This command will build and start our tutorial
service in a container. The --build
option is used to build the container before starting it. Once the container is running, you should see output similar to the following:
tutorial_1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
tutorial_1 | INFO: Started reloader process [1] using watchgod
tutorial_1 | INFO: Started server process [3]
tutorial_1 | INFO: Waiting for application startup.
tutorial_1 | INFO: Application startup complete.
- Test the application
With the container running, you can test the application by opening a web browser and navigating to http://localhost:8000
. You should see the following output:
FASTAPI Docker Tutorial
Welcome to the FASTAPI Docker Tutorial!
Congratulations! You have successfully containerized a Python FastAPI application development using Docker and docker-compose
.
- Stop the container
To stop the container, use the following command in the same terminal session where you ran docker-compose up
:
docker-compose down
This command will stop and remove the containers and networks created by docker-compose up
.
Top comments (1)
adding --host solves issue at my end. Thanks.