Skip to content

6.4. Containers

A container is a lightweight, portable package that includes your application and everything it needs to run - code, libraries, dependencies, and configuration.

Docker is the most widely used container technology.

Instead of worrying about whether code will behave differently on your laptop, a server, or in the cloud, containers guarantee that your application runs the same way everywhere.


Why use Containers?

  • Ease - Cloud platforms have services for deploying containers
  • Consistency – no more "it worked on my machine" problems
  • Portability – run the same model or pipeline locally, in testing, and in production without change
  • Isolation – dependencies are separated, so one project's setup won't break another
  • Scalability – containers can be replicated to handle large volumes (e.g. running impact analysis across millions of quotes)
  • Integration – containers slot neatly into CI/CD pipelines for smooth deployment

Workflow with Docker

  1. Write your code – e.g. Python scripts for data prep and model training
  2. Create a Dockerfile – specify Python version, required packages, and how to run the app
  3. Build the container – package everything into a single Docker image
  4. Run it anywhere – locally, on a server, or in the cloud
  5. Deploy at scale – containers can be managed with orchestration tools like Kubernetes or Azure Container Apps

Installing Docker

The likeliest scenario will be installing Docker on Windows, and using WSL as a backend.

The documentation for this can be found here

Example Dockerfile

# Starts from a minimal Python 3.12 image. Using a slim image keeps the container lightweight while including Python and essential system libraries.
FROM python:3.12-slim

# Sets `/app` as the working directory inside the container. All subsequent commands (like `COPY` and `RUN`) are executed from this folder.
WORKDIR /app

# Copies the `pyproject.toml` file into the container. Copying this first allows Docker to cache dependency installation if `pyproject.toml` hasn’t changed, which speeds up rebuilds.
COPY pyproject.toml .

# Sets an environment variable used by `uv` to know which Python version to use when installing and running dependencies.
ENV UV_PYTHON=python3.12

# Installs the `uv` dependency manager (similar to Poetry or Pipenv).  
#  `uv sync --no-dev` reads `pyproject.toml` and installs all project dependencies into the container.  
#  `--no-cache-dir` ensures pip does not store cache files, keeping the image smaller.
RUN pip install --no-cache-dir uv && \
    uv sync --no-dev

# Copies your application code into the container at `/app/demo_code`. This ensures the container has everything needed to run the FastAPI app.
COPY ./demo_code ./demo_code

# Informs Docker that the container will listen on port 80. This port will be mapped to the host or cloud environment when the container runs.
EXPOSE 80

#   Defines the default command to start the FastAPI app using Uvicorn via `uv`.  
#  - `0.0.0.0` allows the app to accept connections from any network interface.  
#  - Port `80` matches the exposed container port.  
#  - Using `uv` simplifies running Python apps and ensures dependencies from `pyproject.toml` are used correctly.
CMD ["uv", "run", "uvicorn", "demo_code.fast_api:app", "--host", "0.0.0.0", "--port", "80"]

Building an image

docker build -t pricing-app .
  • -t pricing-app names the image pricing-app.

  • . tells Docker to look for the Dockerfile in the current directory.

  • Docker will execute all commands in the Dockerfile to create a portable image containing your code and dependencies.

Run the container locally

docker run -p 80:80 pricing-app
  • -p 80:80 maps the container’s port 80 to your local machine, allowing you to access the FastAPI app in a browser at http://localhost:80.

  • This command executes the CMD from the Dockerfile (uvicorn app:app --host 0.0.0.0 --port 80).

Verify the app is running locally:

curl http://localhost:80/calculate_premium

The same API call can be made as when running FastAPI directly in the previous chapter.

Pushing your image

To deploy the image, it needs to be pushed to a container registry.

Some cloud hosted registries include: - Docker Hub - Amazon Elastic Container Registry (ECR) - Azure Container Registry (ACR) - GitHub Container Registry / GitHub Packages

To push the image to Azure:

This sets up an Azure Container Registry named fastapiregistry.

az acr login --name fastapiregistry
az acr create --resource-group demo-fastapi --name fastapiregistry --sku Basic

Tagging tells Docker where to push the image and what name it should have in the registry.

docker tag pricing-app:latest pricingdemofastapiregistry.azurecr.io/pricing-app:latest

This uploads the image to the registry so it can be deployed elsewhere.

docker push pricingdemofastapiregistry.azurecr.io/pricing-app:latest