How to Deploy Air Applications with Docker and Kubernetes: Production Guide

Deploy Air applications by building a multi-stage Docker image using examples/containerize/Dockerfile and applying the production-ready Kubernetes manifest from examples/deployment/k8s/deployment.yaml with customized health probes and security contexts.

Air is a lightweight Python web framework built on FastAPI, Pydantic, and HTMX that runs on an ASGI server (typically uvicorn). The feldroy/air repository provides ready-to-use containerization and orchestration configurations that package Air apps as minimal containers and deploy them to Kubernetes clusters with proper health checks, security defaults, and multi-platform support.

Containerizing Air Applications with Docker

The repository includes a production-hardened Dockerfile at examples/containerize/Dockerfile that implements a multi-stage build pattern. This approach separates dependency installation from the runtime environment to create minimal, secure images.

Multi-Stage Build Configuration

The build stage uses the ghcr.io/astral-sh/uv:python3.14-bookworm-slim image to install Python dependencies into a virtual environment (.venv). The runtime stage then copies this environment and your application code into a stripped-down python:3.14-slim-bookworm image. This eliminates build tools from the final container, reducing attack surface and image size.

Runtime Security and Health Checks

The runtime stage creates a non-root appuser, exposes port 8000, and launches uvicorn with multiple workers. The container expects an HTTP endpoint at /health that returns a 2xx status code for orchestrator health verification. Air apps can expose this via a standard FastAPI route:

import air

app = air.Air()

@app.get("/health")
def health() -> dict:
    return {"status": "ok"}

Building Multi-Platform Images for Kubernetes

Because Kubernetes clusters often run mixed node architectures (AMD64 and ARM64), the Dockerfile supports Docker Buildx for creating cross-platform images. This ensures your Air application runs on any node pool without emulation overhead.

Enable BuildKit and create a multi-platform build:

export DOCKER_BUILDKIT=1

docker buildx create --use

docker buildx build \
    --platform linux/amd64,linux/arm64 \
    -t ghcr.io/your-user/air-app:1.0.0 \
    --push .

Push the resulting image to any container registry (Docker Hub, GitHub Container Registry, Quay, or private registries) so your Kubernetes cluster can pull it.

Kubernetes Deployment Configuration

The manifest at examples/deployment/k8s/deployment.yaml defines a complete, production-ready stack including Deployment, Service, Ingress, ConfigMap, and Secret objects. This allows a single kubectl apply command to deploy your entire Air application infrastructure.

Core Manifest Components

  • Deployment: Runs the Air container as a non-root pod with defined resource requests and limits
  • Service: Exposes the application on port 80 within the cluster
  • Ingress: Includes Traefik-specific annotations (replace with Nginx, Istio, or other ingress controller configurations as needed)
  • ConfigMap & Secret: Inject configuration values and sensitive data without baking them into the image

Health Probes and Security Context

The manifest configures liveness and readiness probes that query HTTP endpoints to determine pod health. While the sample uses /, you should customize these to point to your dedicated health endpoints:

livenessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 5
  periodSeconds: 30

readinessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 5
  periodSeconds: 10

The security context runs containers as non-root with restricted permissions, following the principle of least privilege.

Required Customization Points

Before applying the manifest, modify these specific fields in examples/deployment/k8s/deployment.yaml:

  • metadata.name: Replace air-app with your service identifier
  • spec.replicas: Set the desired number of pod instances
  • containers.image: Update hardwyrd/air-blogdemo:0.39.0 to your registry path and tag
  • Probe paths: Change / to /health and /ready (or your custom endpoints)

Production Deployment Workflow

Follow this sequence to deploy Air applications from code to cluster:

  1. Implement health endpoints in your main.py (as shown in the Containerizing section).

  2. Build and push the multi-platform image to your registry:

    docker buildx build \
        --platform linux/amd64,linux/arm64 \
        -t ghcr.io/your-user/your-air-app:latest \
        --push .
  3. Customize the manifest by editing examples/deployment/k8s/deployment.yaml with your application name, image reference, replica count, and probe paths.

  4. Deploy to the cluster:

    kubectl apply -f examples/deployment/k8s/deployment.yaml -n your-namespace
  5. Verify the deployment:

    kubectl get pods -n your-namespace
    kubectl describe pod <pod-name> -n your-namespace
  6. Test locally (optional) before deploying:

    docker run --rm -p 8000:8000 ghcr.io/your-user/your-air-app:latest
    curl http://localhost:8000/health

Summary

  • The examples/containerize/Dockerfile provides a multi-stage build using ghcr.io/astral-sh/uv and python:3.14-slim-bookworm images to create minimal, secure runtime containers
  • Air applications run as non-root users on port 8000 via uvicorn with multiple workers
  • Docker Buildx enables multi-platform builds (linux/amd64, linux/arm64) for heterogeneous Kubernetes clusters
  • The examples/deployment/k8s/deployment.yaml manifest includes Deployments, Services, Ingress rules, and probe configurations ready for production customization
  • Health endpoints at /health (or custom paths) enable proper Kubernetes liveness and readiness checks

Frequently Asked Questions

What base images does the Air Dockerfile use?

The build stage uses ghcr.io/astral-sh/uv:python3.14-bookworm-slim for dependency installation with the uv package manager, while the runtime stage uses python:3.14-slim-bookworm to provide a minimal Python environment. This combination ensures fast builds and small production images (approximately 100MB depending on dependencies).

How do I configure health checks for Air in Kubernetes?

Add a FastAPI route to your main.py that returns HTTP 200, then reference this endpoint in the livenessProbe and readinessProbe sections of examples/deployment/k8s/deployment.yaml. The probes support custom paths, ports, initial delays, and check intervals to match your application's startup behavior.

Can Air containers run as root users?

While technically possible, the provided Dockerfile explicitly creates a non-root appuser and the Kubernetes manifest runs containers with security contexts that discourage root execution. Running as root is unnecessary since uvicorn binds to port 8000 (unprivileged), and avoiding root reduces container escape risks.

How do I expose my Air application to external traffic?

The sample manifest includes Ingress configuration with Traefik annotations. Replace these with annotations specific to your ingress controller (Nginx, Istio, AWS ALB, etc.) and update the host rules to match your domain. The Service object exposes port 80 internally, which the ingress controller routes to the pod's port 8000.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →