🧭 How toSoftwareBeginner✨ AI-assisted

How to Build Small, Fast Docker Images for Python AI Services

WittyTech··2 min read
#docker#python#containers

Python AI services have a reputation for huge container images. A few gigabytes means slow builds, slow deployments and slow scaling when traffic arrives. Most of that size is avoidable.

Step 1: Start from a slim base

Use python:3.12-slim rather than the full image. If your service only calls model APIs, you don't need CUDA or a GPU base image at all. Those add gigabytes and belong only in images that run models locally.

Step 2: Use a multi-stage build

Install dependencies in a build stage and copy only the result into the final image:

FROM python:3.12-slim AS build
COPY --from=ghcr.io/astral-sh/uv:0.8 /uv /bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project

FROM python:3.12-slim
WORKDIR /app
COPY --from=build /app/.venv /app/.venv
COPY src ./src
ENV PATH="/app/.venv/bin:$PATH"
USER nobody
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080"]

Compilers and build tools stay in the first stage and never reach production.

Step 3: Order layers for caching

Copy the dependency files and install them before copying your source code. A code change then rebuilds only the last layers, and the dependency layer comes from cache.

Step 4: Keep models and data out

Don't copy model weights, datasets or notebooks into the image. Add a .dockerignore that excludes .git, data/, notebooks/ and local virtual environments.

Step 5: Run as a non-root user

The USER line stops the process from running as root. Many Kubernetes security policies reject root containers anyway.

Step 6: Check the result

Run docker image ls to see the size and docker history to find the layers that grew. A tool like dive shows exactly which files take up the space.

Things to watch

  • Some packages pull in large optional extras. Install only what you import.
  • Pin the uv image and the base image to specific versions, so builds don't change unexpectedly.
  • Alpine-based images can make Python packages slower to install and harder to debug. Slim Debian images are usually the safer choice.

With these steps, a typical service that calls model APIs fits in a few hundred megabytes.

← More in Software