Run FastAPI on Kubernetes

Khimananda Oli 7 min read Programming and Languages
Run FastAPI on Kubernetes

By Khimananda Oli | Last reviewed: August 2026

Deploying Python APIs often fails at the container boundary because developers treat orchestration as an afterthought rather than a core architectural constraint. To successfully run FastAPI on Kubernetes, you must align your application’s asynchronous worker model with cluster resource management, ensuring that liveness probes, graceful shutdowns, and horizontal scaling actually function under load. This guide bridges the gap between local development and production-grade orchestration using verified configurations for 2026.

How do you containerize FastAPI for Kubernetes?

The foundation of any stable Kubernetes deployment is a deterministic, lightweight container image. When you prepare to run FastAPI on Kubernetes, avoid using the official python base image directly; it exceeds 900MB and includes unnecessary build tools that increase your attack surface. Instead, use a multi-stage build pattern that separates compilation dependencies from the runtime environment. This approach keeps final images under 200MB and ensures reproducible deployments across environments.

Builder StageInstall Build Depspip install --userCompile ExtensionsCOPY /site-packagesRuntime StageSlim Python BaseCopy App + DepsNon-root UserFinal Image< 200MBSecure & Fast
Multi-stage Docker build architecture for optimizing FastAPI containers before deploying to Kubernetes

A common mistake when configuring the entrypoint is running Uvicorn directly without a process manager. While Uvicorn is an excellent ASGI server, it lacks robust process supervision for production containers. Use Gunicorn with the Uvicorn worker class to handle graceful restarts, signal forwarding, and multiple worker processes within a single pod. This combination is currently the industry standard for async Python workloads in orchestrated environments.

# Dockerfile.production
FROM python:3.12-slim-bookworm AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

FROM python:3.12-slim-bookworm
RUN useradd --create-home appuser
WORKDIR /home/appuser
COPY --from=builder /install /usr/local
COPY ./app ./app
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]

For teams managing complex dependency trees or integrating with databases like PostgreSQL, understanding PostgreSQL administration essentials helps prevent connection pool exhaustion when scaling pods. Each replica opens its own set of database connections, so your container strategy must account for backend capacity, not just CPU and memory limits.

What are the correct Kubernetes manifests for FastAPI?

Writing YAML manifests requires precision, especially when defining health checks and resource boundaries. Many engineers struggle to correctly debug a CrashLoopBackOff in Kubernetes because they misconfigure probe timing or fail to distinguish between startup, liveness, and readiness checks. For FastAPI, your probes should target lightweight endpoints that verify both the web server and critical downstream dependencies without executing heavy business logic.

Configuring Health Probes and Resources

Your FastAPI application must expose dedicated health endpoints. The /health/live endpoint should return 200 OK immediately if the process is responsive, while /health/ready should validate database connectivity and cache availability. Setting appropriate initialDelaySeconds prevents premature restarts during cold starts, and periodSeconds determines how quickly the cluster detects failures.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
      - name: api
        image: registry.example.com/fastapi-app:v1.4.2
        ports:
        - containerPort: 8000
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "1000m"
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /health/live
            port: 8000
          initialDelaySeconds: 10
          periodSeconds: 15
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 10

Resource requests and limits are non-negotiable for Python workloads. Without them, the scheduler cannot make informed placement decisions, and a single memory leak can destabilize an entire node. Always set requests based on observed baseline usage and limits at 2x–4x the request value to accommodate garbage collection spikes. Refer to our guide on Kubernetes resource limits and requests for detailed tuning strategies specific to interpreted languages.

How does autoscaling work for async Python APIs?

Horizontal Pod Autoscaling (HPA) behaves differently for asynchronous frameworks compared to traditional synchronous ones. Because FastAPI handles concurrency via event loops rather than thread-per-request models, CPU utilization often remains low even under high throughput. Relying solely on CPU metrics leads to under-scaling and increased latency. You should implement custom metrics based on active requests or queue depth to trigger scaling events accurately.

Traffic Spike10k req/sCPU Metric OnlyAsync = Low CPU❌ No Scale EventCustom MetricsActive Requests✅ Scale Up TriggeredHPA ControllerAdjust ReplicasBased on Target ValueResult: Stable Latency Under LoadPods scale proportionally to actual workload demand
Autoscaling decision flow demonstrating why custom metrics outperform CPU-only HPA for async FastAPI applications

To expose custom metrics, integrate Prometheus client libraries into your FastAPI application and configure the Prometheus Adapter in your cluster. Define HPA targets against these metrics rather than generic resource consumption. This ensures your infrastructure responds to real user experience degradation rather than arbitrary system statistics. Remember that scaling also affects downstream services; always coordinate API scaling with database connection pooling and cache layer capacity.

How do you manage secrets and configuration safely?

Hardcoding credentials in Dockerfiles or mounting unencrypted ConfigMaps violates basic security principles and compliance standards like SOC 2. When you run FastAPI on Kubernetes, sensitive values such as database passwords, API keys, and JWT signing secrets must be injected securely at runtime. Native Kubernetes Secrets provide base64 encoding but not encryption at rest by default. For production environments, integrate external secret managers or enable encryption at rest on the etcd datastore.

  • Use environment variables for simple configuration toggles and non-sensitive metadata.
  • Mount secrets as files rather than env vars to prevent leakage in process listings and crash dumps.
  • Implement least-privilege RBAC policies so only specific service accounts can access required secrets.
  • Rotate credentials automatically using operators or external sync tools without redeploying pods.
  • Audit secret access patterns through centralized logging to detect anomalous behavior early.

For comprehensive guidance on securing sensitive data, review our article on Kubernetes secrets management done right. Proper secret handling is frequently the difference between passing and failing security audits, especially for fintech and healthcare applications operating in regulated markets.

When should you use Ingress versus LoadBalancer?

Exposing your FastAPI service requires choosing the right networking primitive. A LoadBalancer Service provisions a cloud provider's external load balancer per service, which becomes cost-prohibitive beyond two or three services. An Ingress Controller consolidates routing rules behind a single entry point, enabling path-based routing, TLS termination, and rate limiting at the edge. For most production deployments, Ingress is the economically and operationally superior choice.

CriteriaLoadBalancer ServiceIngress Controller
Cost EfficiencyHigh (one LB per service)Low (shared LB for many services)
TLS TerminationPer-service certificate managementCentralized cert-manager integration
Path-Based RoutingNot supported nativelyNative support via rules
Rate LimitingRequires external middlewareBuilt-in annotations or CRDs
ComplexitySimple, zero configModerate, requires controller setup

If you're still evaluating whether Kubernetes is necessary for your current scale, compare it against simpler alternatives discussed in our Kubernetes vs Docker Swarm comparison. Not every FastAPI project needs full orchestration, but once you exceed single-node reliability requirements, Kubernetes provides unmatched operational leverage.

External UsersHTTPS TrafficIngress ControllerTLS + RoutingFastAPI Pods (ReplicaSet)Pod 1Pod 2Pod NShared ConfigMap + SecretsPostgreSQLManaged DBObservabilityPrometheus + GrafanaMetrics
Complete production architecture for running FastAPI on Kubernetes with ingress, stateful backends, and monitoring

Run FastAPI on Kubernetes With Confidence

Successfully operating async Python APIs in production demands disciplined attention to containerization, probe configuration, metric selection, and secret hygiene. By following the patterns outlined here, you eliminate the most frequent failure modes that plague teams attempting to run FastAPI on Kubernetes for the first time. Start with the multi-stage Dockerfile and validated manifests above, then iterate based on observed performance data rather than assumptions. If your team needs hands-on assistance designing compliant, scalable API infrastructure, reach out to discuss your specific requirements.

Frequently Asked Questions

Use a multi-stage Dockerfile with python:3.12-slim. Install dependencies in the first stage, then copy only the app and virtual environment to the final image. Run Uvicorn with four workers on port 8000 using CMD.

Python slim or distroless images work best. They reduce attack surface and image size significantly compared to full Debian builds while maintaining compatibility with most FastAPI dependencies and native extensions required by your application stack.

Set workers equal to available CPU cores minus one. For a two-core limit, use three workers. This prevents context switching overhead while maximizing throughput without causing memory pressure or OOM kills in constrained Kubernetes environments.

No, Uvicorn alone handles production traffic efficiently. Gunicorn adds unnecessary latency and memory overhead. Configure Uvicorn workers directly via command line flags or environment variables for simpler debugging and better async performance.

Expose a lightweight /health endpoint returning 200 OK. Configure livenessProbe and readinessProbe in your deployment manifest pointing to this path with appropriate initialDelaySeconds and periodSeconds values to prevent premature restarts during startup.

Start with 256Mi memory and 500m CPU requests. Monitor actual usage with Prometheus metrics for two weeks before adjusting. FastAPI apps typically consume less than Node.js but require tuning based on payload size and concurrency patterns.

Mount Kubernetes Secrets as environment variables or files. Use ConfigMaps for non-sensitive settings. Never hardcode credentials. Consider external secret operators like External Secrets Operator for syncing from AWS Secrets Manager or HashiCorp Vault automatically.

Yes, use Horizontal Pod Autoscaler targeting custom metrics like request rate or queue depth instead of just CPU. FastAPI stateless design enables instant scaling. Ensure session data lives in Redis or databases, not pod memory.

Create a Service of type ClusterIP, then configure an Ingress resource with NGINX or Traefik controller. Add TLS termination at the ingress level. Use path-based routing if hosting multiple FastAPI services under one domain.

Output structured JSON logs to stdout. Include trace_id, timestamp, and log_level fields. Avoid file logging since pods are ephemeral. Let Fluent Bit or Vector collect and forward logs to your observability backend automatically.

Enable OpenTelemetry tracing with automatic instrumentation. Check p99 latency in Grafana dashboards. Profile database queries and external API calls separately. Verify network policies are not adding latency between pods and dependent services within the cluster.

Generally yes for concurrent workloads. FastAPI async support handles thousands of simultaneous connections per pod versus Flask synchronous model. Benchmarks show three to five times higher throughput for IO-bound tasks under identical Kubernetes resource constraints.

Use an initContainer in your deployment that runs Alembic upgrade head. The main container waits until the init container completes successfully. This ensures schema changes apply exactly once before any FastAPI pod serves traffic.

Run containers as non-root user with readOnlyRootFilesystem enabled. Drop all Linux capabilities except NET_BIND_SERVICE if needed. Scan images with Trivy in CI pipeline. Restrict network policies to allow only required service-to-service communication paths.

Costs vary by cloud provider and scale. A minimal three-node cluster runs roughly fifty to eighty dollars monthly. Optimize with spot instances and right-sizing. Small teams often save money using managed platforms like Fly.io or Render instead.