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: Replaceair-appwith your service identifierspec.replicas: Set the desired number of pod instancescontainers.image: Updatehardwyrd/air-blogdemo:0.39.0to your registry path and tag- Probe paths: Change
/to/healthand/ready(or your custom endpoints)
Production Deployment Workflow
Follow this sequence to deploy Air applications from code to cluster:
-
Implement health endpoints in your
main.py(as shown in the Containerizing section). -
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 . -
Customize the manifest by editing
examples/deployment/k8s/deployment.yamlwith your application name, image reference, replica count, and probe paths. -
Deploy to the cluster:
kubectl apply -f examples/deployment/k8s/deployment.yaml -n your-namespace -
Verify the deployment:
kubectl get pods -n your-namespace kubectl describe pod <pod-name> -n your-namespace -
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/Dockerfileprovides a multi-stage build usingghcr.io/astral-sh/uvandpython:3.14-slim-bookwormimages 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.yamlmanifest 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →