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-C
1.
We can use docker stop to stop the container instead:
docker stop hello-world