Purpose
Create and setup a python development environment inside of docker in 5 minutes. (Also more or less a journal to myself of how to do this)
Updated June 2026 — bumped to Python 3.13, fixed a few bugs the comments caught, and updated Docker Compose v1 → v2.
What to know
You will need to understand virtual environments with python. I will place the commands that are needed for setting up the virtual environment but will not expand upon them.
What you need
Python 3.13 is the version I'll be using in this tutorial.
Python modules you will need are:
- fastapi
- hypercorn
A few files will need to be created:
- main.py
- Dockerfile
- .dockerignore
- docker-compose.yml
The following commands will create the project directory and the initial files we'll need for the app:
mkdir -p ~/projects/myproject
cd ~/projects/myproject
touch main.py Dockerfile .dockerignore docker-compose.yml
python3 -m venv .venv
source .venv/bin/activate
pip install fastapi hypercorn
pip freeze > requirements.txt
This creates a virtual environment and generates requirements.txt for the Docker build. You can swap ~/projects/myproject with whatever directory you want to use.
The files
Now to modify the files you just created. Let's start with the FastAPI application.
main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def index():
return {"key": "value"}
Pretty straightforward—import FastAPI, instantiate the app, add a route, return a dict.
Dockerfile:
FROM python:3.13-slim
WORKDIR /app/
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app/
EXPOSE 8005
CMD ["hypercorn", "main:app", "--bind", "0.0.0.0:8005", "--reload"]
This pulls python:3.13-slim as the base image. It installs dependencies first (so Docker can cache that layer), then copies the rest of the app. Port is set to 8005 and Hypercorn serves the app with hot-reload enabled.
.dockerignore:
You don't need the .venv folder or __pycache__ in the image, so add these:
.venv/
__pycache__/
docker-compose.yml:
services:
api:
build: .
image: fastapiapp:latest
ports:
- 8005:8005
volumes:
- type: bind
source: .
target: /app/
This tells Docker Compose to build from the Dockerfile, expose port 8005, and mount your current directory into the container as a bind mount so code changes are reflected immediately.
Putting it all together
To build and run:
docker compose build && docker compose up -d
The first build will take a minute while it downloads the base image and installs dependencies. After that, Docker's build cache will make subsequent builds nearly instant.
The app should be accessible at http://127.0.0.1:8005 and should return {"key":"value"}.
I chose port 8005 because I had containers on the previous five ports. Use whatever port works for you — the mapping is hostport:containerport.
Bind mounts let you edit code locally and see changes in the container without rebuilding. The only time you'll need to rebuild is when you add new Python modules — run pip freeze > requirements.txt after installing and rebuild.
Helper scripts
build.sh:
docker build --pull --rm -f "Dockerfile" -t fastapiapp:latest "."
up.sh:
docker compose -f "docker-compose.yml" up -d --build
Things to check when it all goes wrong
- Is port 8005 open on your firewall (at least for local connections)?
- Is the container running?
docker ps— the image name should befastapiapp:latest - Check the logs:
docker logs -f fastapiapp— the issue is usually visible pretty clearly
GitHub repo
All of the above files are in the repository on my GitHub.
Top comments (12)
Don't you mean "source .venv/bin/activate", not "source .venv/bin/python"?
A couple of further minor points - your (optional?) "EXPOSE 8005" line should be "8000", shouldn't it? There's also a typo in the "docker-compose" line where you have "buid" rather than "build".
In the first code example you create a virtual environment but do not activate it. This would result in you installing fastapi and hypercorn into the system python which is probably not what you wanted.
Aye, you're right. Thanks for pointing that out.
This is a game-changer! Using Docker for Python development is a brilliant idea. This setup will streamline workflows and ensure consistency across environments. A must-try for any Python development services!
Thanks this was helpful.
Great walkthrough! This blog clearly explains how to set up a FastAPI development environment with Docker in just minutes. The step-by-step approach—covering virtual environments, Dockerfile, docker-compose, and bind mounts—makes it beginner-friendly yet practical. The helper scripts and troubleshooting tips are especially useful for smooth DevOps workflows.
Ok, makes sense now. Thanks for the feedback :)
Glad I could help. I will try to make the post a little more clear about that, I can see from the title now that it's kind of misleading.
Why create a venv inside a container? I mean your python environment is already isolated by the container, why introduce a not needed layer of abstraction? Just curious :)
You're not actually setting up a virtual environment inside the container. The container ultimately ends up being your end product. You can write your code and build your container and push it to the cloud/your server/github/dockerhub etc. It effectively sets up a CICD workflow. I will try to make this clearer in the post above but if you look at the Dockerfile you're not actually setting up a virtual environment inside the container. The only thing you do inside the container is install the required modules for your app to run and updating your codebase. Once your push that container to your server for example it can be live. No need to setup any kind of environments on your server it's all containerized.
“Python’s simplicity and versatility make it a must-know for developers and data scientists alike.”
“A powerful language for automation, data analysis, and AI—Python never disappoints.”
Some comments may only be visible to logged-in visitors. Sign in to view all comments.