Your Sunday, upgraded. Free live AI class · 5 PM ISTReserve your seat
DEVOPS & TOOLING

Containerise a Python API with Docker, from First Build to Deployment

This guide packages a small FastAPI service into a production-ready container. It covers the Dockerfile, local development with Compose, configuration, health checks and what to verify before deploying.

On this page

What you are building

The service exposes a few endpoints for course data and depends on PostgreSQL. The goals are a small image that builds quickly, starts the same way everywhere, reads configuration from the environment and can be checked by the platform for health. The same principles apply to Flask, Django or any other Python web framework.

Write the Dockerfile

Order instructions so slow, rarely changing steps come first. Copy only the dependency file before installing, then copy the source. Run the application as a non-root user.

FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app ./app
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

PYTHONUNBUFFERED makes logs appear immediately in container output. Choose the Python version your project is tested against and pin it in the tag.

Exclude what does not belong

Create a .dockerignore listing .git, .venv, __pycache__, test data, local environment files and editor folders. This speeds up builds by shrinking the context sent to Docker and keeps secrets and personal files out of the image.

Run locally with Compose

Docker Compose describes the API and database together. Give the database a named volume so data survives restarts, and pass configuration through environment variables.

services:
  api:
    build: .
    ports: ["8000:8000"]
    environment:
      DATABASE_URL: postgresql://app:app@db:5432/app
    depends_on: [db]
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    volumes: ["pgdata:/var/lib/postgresql/data"]
volumes:
  pgdata:

These credentials are for local development only. In production, secrets come from the platform's secret store, never from a committed file. Note that depends_on controls start order, not readiness, so the API should retry its database connection briefly at startup.

Add a meaningful health check

Expose two endpoints: a liveness endpoint that returns success if the process is running, and a readiness endpoint that also checks the database connection. Platforms use readiness to decide when to send traffic, so a container that cannot reach its database is kept out of rotation instead of returning errors to users.

Configure through the environment

Read every setting, including the database URL, allowed origins and log level, from environment variables, validated once at startup. The same image then moves unchanged from development to staging to production, with only configuration differing. Rebuilding the image per environment makes it impossible to be sure that what you tested is what you deployed.

Verify before deploying

  • Build from a clean checkout and confirm the image size is reasonable.
  • Run the container with production-like environment variables and call the readiness endpoint.
  • Confirm the process runs as the non-root user.
  • Scan the image for known vulnerabilities with your registry or a scanning tool.
  • Check that logs go to standard output and no secrets appear in them.
  • Tag the image with the commit SHA or release version, not only latest.

Checklist

  • Dependencies install before the source is copied
  • A .dockerignore keeps the context small and clean
  • The container runs as a non-root user
  • Data lives in volumes or managed services
  • Liveness and readiness are separate checks
  • One image is promoted through environments by configuration

Share or cite this guide

Innovate with Ajay Editorial (2026-10-07). Containerise a Python API with Docker, from First Build to Deployment. https://innovatewithajay.com/articles/containerise-a-python-api-with-docker

Editorial approach, sources and corrections

YOUR NEXT CHAPTER

You have the curiosity.
Let’s turn it into capability.

Start with a practical workshop or bring a specific question to Ajay.

Chat with Ajay