Skip to main content
  1. Posts/

How to Deploy Fastapi Application with Docker

·508 words·3 mins·
Table of Contents

In post, I want to summarize the complete steps to deploy a demo web service implemented with FastAPI in Docker container.

Create the service
#

Preparations
#

First, we can create the simple project and a Python virtual environment:

mkdir fastapi-hello-world
cd fastapi-hello-world

# create the virtual environment
python -m venv venv

# activate the virutal env
source venv/bin/activate

Install all the packages we need for the development:

pip install fastapi uvicorn

FastAPI is the web framework and Uvicorn is used as the web server for handling requests.

Build the simple application
#

Create a file named application.py (the filename does not matter):

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def greet():
    return {"status": "ok", "message": "hello world!"}

You can run it locally to make sure that it works:

uvicorn application:app --host 0.0.0.0 --port 1234

For --host option, we use 0.0.0.0, which tells the server to accept connection from anywhere, not just the localhost. Without --host 0.0.0.0, you can only request this service using localhost. This is especially important when we later dockerize the application. Without the --host option, you can not request this service in your host computer or other network.

The --port option specifies the port that this service will listen to. If you do not specify it, the default will be port 8000.

To avoid typing the command, we can create a start_service.sh script to start the service:

uvicorn application:app --host 0.0.0.0 --port 1234

Dockerize the service
#

Generate requirements.txt
#

We need to create a requirements.txt file for the dependencies:

pip freeze > requirements.txt

create Dockerfile
#

The Docker file looks like this:

FROM python:3.10-slim

WORKDIR /app
COPY ./requirements.txt /app
COPY ./ /app

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

EXPOSE 1234
CMD ["/bin/bash", "start_service.sh"]

Do not use only EXPOSE to try to expose an internal port, it does not work. The official doc about EXPOSE is clear on this:

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

So we should use -p to map the internal port to port in the host machine.

Build docker image and run
#

To build the image, run:

docker build -t fastapi-hello-world .
# for example, docker build -t hello-world .

It will build the image based on the Dockerfile.

To start the web service, we can run the following command:

docker run -p 1234:1234 --rm --name hello-world fastapi-hello-world

Then you can request this service in your browser using http://127.0.0.1:1234.

The service cannot be stopped by using Ctrl-C1. We can use docker stop to stop the container instead:

docker stop hello-world

references
#


  1. Adding -it option to docker run can also solve this issue, also discussed here↩︎

Related

FastAPI testing and OpenAPI doc generation
··239 words·2 mins
How to Parse Query Param With Multiple Values in FastAPI
·316 words·2 mins
Configure Python logging with dictConfig
··503 words·3 mins