FastAPI Docker Build Comparison
Overview
FastAPI Docker Build Comparison
Overview
This project replicates the multi-stage Docker build experiments performed for the Spring Boot service, but using Python + FastAPI. The FastAPI backend connects to PostgreSQL, reads configuration from environment variables (loaded via .env), and exposes simple REST APIs for demonstration.
The objective is to compare Docker image sizes and workflows between:
- Single-Stage Build — build and run directly inside one image.
- Multi-Stage Build — build wheels in a builder stage, install in a minimal runtime stage.
- Runtime Artifact Build — build the wheel externally (on host/CI) and produce a small runtime image.
Application Overview
The FastAPI app provides simple endpoints for reading environment variables and interacting with PostgreSQL via SQLAlchemy.
Endpoints
Endpoint Method Description /api/hello GET Returns greeting, owner, and JVM-style env info. /api/notes GET Returns all notes stored in the database. /api/notes POST Adds a new note to PostgreSQL.
Environment Variables
Variable Description Example POSTGRES_HOST PostgreSQL host name mypgdb POSTGRES_PORT PostgreSQL port 5432 POSTGRES_DB Database name mainschema POSTGRES_USER Username postgres POSTGRES_PASSWORD Password admin APP_GREETING Custom greeting message Hello from FastAPI APP_OWNER Application owner name Ashfaq JVM_XMS Placeholder (for parity with Java demo) 256m JVM_XMX Placeholder (for parity with Java demo) 512m
All environment variables are loaded automatically from the .env file during local development.
PostgreSQL Configuration
A PostgreSQL container was already running externally:
docker ps
CONTAINER ID IMAGE PORTS NAMES
be2f402a601c postgres:latest 0.0.0.0:9991->5432/tcp mypgdb
To enable communication between backend containers and this database, a shared Docker network was created and both containers were attached to it:
docker network create mynet
docker network connect mynet mypgdb
Within the containers, PostgreSQL is referenced as mypgdb:5432.
Docker Build Strategies
1. Single-Stage Build (Dockerfile.single)
Purpose: Install dependencies and run directly in one image.
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Build & Run:
docker build -f Dockerfile.single -t fastapi-env-demo:single .
docker run -d \
--name fastapi-single \
--network mynet \
-p 8000:8000 \
-e POSTGRES_HOST=mypgdb \
-e POSTGRES_PORT=5432 \
-e POSTGRES_DB=mainschema \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=admin \
-e APP_GREETING="Hello from FastAPI Single" \
-e APP_OWNER="Ashfaq" \
fastapi-env-demo:single
Image Size: 273 MB Status: ✅ Working
2. Multi-Stage Build (Dockerfile.multistage)
Purpose: Build wheels in a builder stage and install in a minimal runtime image.
# Builder Stage
FROM python:3.11-slim AS builder
WORKDIR /build
COPY setup.py requirements.txt /build/
COPY app /build/app
RUN pip wheel --no-cache-dir --wheel-dir /build/dist -r requirements.txt .
# Runtime Stage
FROM python:3.11-slim
RUN useradd --create-home --shell /bin/bash appuser
WORKDIR /app
COPY --from=builder /build/dist /dist
RUN pip install --no-cache-dir /dist/*.whl
COPY app /app/app
ENV PYTHONPATH=/app
EXPOSE 8000
USER appuser
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Build & Run:
docker build -f Dockerfile.multistage -t fastapi-env-demo:multistage .
docker run -d \
--name fastapi-multistage \
--network mynet \
-p 8001:8000 \
-e POSTGRES_HOST=mypgdb \
-e POSTGRES_PORT=5432 \
-e POSTGRES_DB=mainschema \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=admin \
-e APP_GREETING="Hello from FastAPI Multi" \
-e APP_OWNER="Ashfaq" \
fastapi-env-demo:multistage
Image Size: 225 MB Status: ✅ Working
3. Runtime Artifact Build (Dockerfile.runtime)
Purpose: Build the wheel externally, copy it into the Docker image, and install it in a minimal runtime image.
FROM python:3.11-slim
RUN useradd --create-home --shell /bin/bash appuser
WORKDIR /app
# copy wheel built on host
COPY *.whl /dist/
RUN pip install --no-cache-dir /dist/*.whl
# optional source copy for debugging
COPY app /app/app
ENV PYTHONPATH=/app
EXPOSE 8000
USER appuser
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Build & Run:
# build the wheel on host
python -m pip wheel --no-deps --wheel-dir dist .
# build docker image
docker build -f Dockerfile.runtime -t fastapi-env-demo:artifact .
docker run -d \
--name fastapi-artifact \
--network mynet \
-p 8002:8000 \
-e POSTGRES_HOST=mypgdb \
-e POSTGRES_PORT=5432 \
-e POSTGRES_DB=mainschema \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=admin \
-e APP_GREETING="Hello from FastAPI Artifact" \
-e APP_OWNER="Ashfaq" \
fastapi-env-demo:artifact
Image Size: 208 MB Status: ✅ Working
Image Size Summary
Build Type Tag Image Size Notes Single-Stage fastapi-env-demo:single 273 MB Easiest but largest Multi-Stage fastapi-env-demo:multistage 225 MB Smaller, optimized build process Runtime Artifact fastapi-env-demo:artifact 208 MB Smallest, best for CI/CD pipelines
Networking Note
The PostgreSQL container (mypgdb) was registered to a shared network mynet to allow backend containers to connect directly without host port mapping.
docker network create mynet
docker network connect mynet mypgdb
POSTGRES_HOST=mypgdb
POSTGRES_PORT=5432
POSTGRES_DB=mainschema
The application containers connect to PostgreSQL using:
Conclusion
- Single-Stage Build: Simple but heavy image (273 MB).
- Multi-Stage Build: Efficient balance (225 MB) — best for reproducible builds.
- Runtime Artifact Build: Lightest (208 MB) — ideal for CI/CD pipelines using pre-built artifacts.
The FastAPI application successfully connected to the PostgreSQL container via the shared Docker network (mynet) and read configuration from environment variables loaded by .env. All three build methods worked, with progressively smaller image footprints and improved build efficiency.
메타데이터
- post_id
- 8317d8942e3e
- slug
- fastapi-docker-build-comparison-8317d8942e3e
- url
- https://medium.com/@ashfaqbs/fastapi-docker-build-comparison-8317d8942e3e
- canonical_url
- https://medium.com/@ashfaqbs/fastapi-docker-build-comparison-8317d8942e3e
- author_url
- https://medium.com/@ashfaqbs
- status
- ok
- fetched_at
- 2026-06-17 08:20:12