DEV Community

Cover image for Getting Started with FastAPI + Docker: A Beginner-Friendly Cloud Setup
Stella Achar Oiro
Stella Achar Oiro

Posted on

Getting Started with FastAPI + Docker: A Beginner-Friendly Cloud Setup

Are you getting into cloud-native development and looking for a real-world project to sharpen your skills? Most FastAPI tutorials show you the basics, but miss the production considerations that matter in actual deployments.

In this guide, I'll walk you through building and containerizing a FastAPI app with Docker—including the production best practices I learned while building healthcare applications and preparing for cloud certifications.

I used this exact approach in my sepsis prediction application and other healthcare systems where reliability and security aren't optional.

Why FastAPI + Docker?

FastAPI paired with Docker gives you:

  • Asynchronous performance for handling multiple requests
  • Automatic API documentation (crucial for team collaboration)
  • Type safety with Python type hints
  • Consistent environments across development, testing, and production
  • Easy scaling in cloud platforms like AWS ECS or Kubernetes

What You'll Build

A production-ready FastAPI application with:

  • Health checks for monitoring
  • Environment-based configuration
  • Proper logging
  • Security headers
  • Optimized Docker image

Project Structure

fastapi-docker-app/
│
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── config.py
│   └── health.py
├── requirements.txt
├── Dockerfile
└── .env.example
Enter fullscreen mode Exit fullscreen mode

1. Environment Configuration (app/config.py)

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "FastAPI Docker App"
    debug: bool = False
    log_level: str = "INFO"

    class Config:
        env_file = ".env"

settings = Settings()
Enter fullscreen mode Exit fullscreen mode

2. Health Check Module (app/health.py)

from fastapi import APIRouter
import psutil
import time

router = APIRouter()

@router.get("/health")
def health_check():
    return {
        "status": "healthy",
        "timestamp": time.time(),
        "memory_usage": f"{psutil.virtual_memory().percent}%",
        "cpu_usage": f"{psutil.cpu_percent()}%"
    }

@router.get("/ready")
def readiness_check():
    # Add database connectivity checks here in real apps
    return {"status": "ready"}
Enter fullscreen mode Exit fullscreen mode

3. Main Application (app/main.py)

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import logging
import time

from .config import settings
from .health import router as health_router

# Configure logging
logging.basicConfig(level=settings.log_level)
logger = logging.getLogger(__name__)

app = FastAPI(
    title=settings.app_name,
    description="A production-ready FastAPI application",
    version="1.0.0",
    docs_url="/docs" if settings.debug else None,
    redoc_url="/redoc" if settings.debug else None
)

# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"] if settings.debug else ["https://yourdomain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["*"],
)

# Include health check routes
app.include_router(health_router, prefix="/api/v1")

@app.middleware("http")
async def add_security_headers(request: Request, call_next):
    response = await call_next(request)
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    return response

@app.middleware("http")
async def log_requests(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    logger.info(f"{request.method} {request.url} - {response.status_code} - {process_time:.3f}s")
    return response

@app.get("/")
def read_root():
    return {
        "message": "Hello from FastAPI + Docker!",
        "app_name": settings.app_name,
        "environment": "development" if settings.debug else "production"
    }

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    logger.error(f"Global exception: {exc}")
    return JSONResponse(
        status_code=500,
        content={"message": "Internal server error"}
    )
Enter fullscreen mode Exit fullscreen mode

4. Dependencies (requirements.txt)

fastapi
uvicorn[standard]
pydantic-settings
psutil
Enter fullscreen mode Exit fullscreen mode

5. Multi-Stage Dockerfile

# Build stage
FROM python:3.11-slim as builder

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

# Production stage
FROM python:3.11-slim

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

WORKDIR /app

# Copy Python dependencies from builder stage
COPY --from=builder /root/.local /home/appuser/.local

# Copy application code
COPY ./app /app

# Change ownership and switch to non-root user
RUN chown -R appuser:appuser /app
USER appuser

# Add local Python packages to PATH
ENV PATH=/home/appuser/.local/bin:$PATH

# Health check
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/api/v1/health || exit 1

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

6. Environment Variables (.env.example)

APP_NAME=FastAPI Docker App
DEBUG=false
LOG_LEVEL=INFO
Enter fullscreen mode Exit fullscreen mode

Build & Run

# Copy environment file
cp .env.example .env

# Build optimized image
docker build -t fastapi-app:latest .

# Run with environment variables
docker run -d \
  --name fastapi-container \
  -p 8000:8000 \
  --env-file .env \
  fastapi-app:latest
Enter fullscreen mode Exit fullscreen mode

Test Your Application

# Basic endpoint
curl http://localhost:8000/

# Health check
curl http://localhost:8000/api/v1/health

# API documentation (if debug=true)
open http://localhost:8000/docs
Enter fullscreen mode Exit fullscreen mode

Common Issues & Solutions

Issue: Container exits immediately

# Check logs
docker logs fastapi-container

# Common fix: Check your environment variables
docker run --env-file .env fastapi-app:latest
Enter fullscreen mode Exit fullscreen mode

Issue: Permission denied errors

  • Make sure you're using the non-root user in Dockerfile
  • Check file permissions on your host system

Issue: Health check failing

# Install curl in container if needed
RUN apt-get update && apt-get install -y curl
Enter fullscreen mode Exit fullscreen mode

Production Deployment Tips

AWS ECS:

  • Use the health check endpoint for load balancer health checks
  • Set appropriate CPU/memory limits
  • Use secrets manager for sensitive environment variables

Kubernetes:

  • Configure liveness and readiness probes using /health and /ready
  • Use ConfigMaps for non-sensitive configuration
  • Implement horizontal pod autoscaling

Docker Compose:

version: '3.8'
services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DEBUG=false
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/health"]
      interval: 30s
      timeout: 10s
      retries: 3
Enter fullscreen mode Exit fullscreen mode

What You've Learned

  • Multi-stage Docker builds for smaller, secure images
  • Health checks and monitoring for production reliability
  • Security headers and middleware for protection
  • Structured logging for debugging
  • Environment-based configuration for different deployment stages
  • Non-root containers for security best practices

Next Steps

  1. Add a database (PostgreSQL with async drivers)
  2. Implement authentication (JWT tokens)
  3. Add rate limiting for API protection
  4. Set up CI/CD with GitHub Actions
  5. Monitor with Prometheus and Grafana

Connect With Me

I'm a software engineer prepping for KCNA and AWS certifications, building healthcare and cloud-native systems using Golang, FastAPI, and Docker. Let's connect.

LinkedIn | GitHub | Substack | More Projects

Top comments (0)