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
- Write your code – e.g. Python scripts for data prep and model training
- Create a Dockerfile – specify Python version, required packages, and how to run the app
- Build the container – package everything into a single Docker image
- Run it anywhere – locally, on a server, or in the cloud
- 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