FastAPI Docker and CI

Introduction

Docker packages FastAPI, dependencies, and Uvicorn into a reproducible image. GitHub Actions runs pytest on every push. This chapter builds a production-oriented Dockerfile, docker compose with MySQL, and CI workflow linked to the Git track.

Prerequisites

Dockerfile

Dockerfile:

Production with workers:

dockerfile
CMD ["gunicorn", "app.main:app", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", "0.0.0.0:8000"]

Build and run:

bash
docker build -t fastapi-app .
docker run -p 8000:8000 \
  -e SECRET_KEY=dev-docker-key \
  -e DATABASE_URL=sqlite:///./app.db \
  fastapi-app

Compare Flask Docker.

.dockerignore

dockerignore
.venv/
__pycache__/
.git/
.env
.pytest_cache/
tests/
*.md

docker compose

docker-compose.yml:

Sync apps may use mysql+pymysql instead of aiomysql—match your SQLAlchemy mode.

Run:

bash
export SECRET_KEY=$(python -c "import secrets; print(secrets.token_hex(16))")
docker compose up --build
curl http://localhost:8000/health

GitHub Actions CI

.github/workflows/fastapi-ci.yml:

Code explanation:

  • Tests use in-memory SQLite via dependency_overrides in conftest.py
  • Remove || true on pip audit when enforcing strictly

Protect main—require CI pass before merge per Git CI/CD.

Deploy Pipeline (Concept)

text
push → CI (pytest) → build image → push registry → server pull → compose up -d

Tag images with Git SHA for rollback.

Migrations in Containers

Run alembic upgrade head in container start command or one-off init job before traffic switch.

Secrets in Compose

Use .env file (gitignored):

env
SECRET_KEY=replace-me
MYSQL_PASSWORD=replace-me

Never commit real passwords in docker-compose.yml.

FAQ

ModuleNotFoundError app.main?

WORKDIR, PYTHONPATH, or missing COPY of package.

DB not ready on start?

depends_on + healthcheck; retry logic optional.

Image too large?

Slim base, multi-stage build, .dockerignore.

CI passes, prod fails?

Prod uses MySQL—add optional MySQL service job in CI for integration tests.

Build and push image in CI?

Add docker/build-push-action after tests on main.

Redis service unused?

Remove from compose until Redis chapter features needed.