Home/Infrastructure/Containerizing a FastAPI App with Docker and Deploying It to Kubernetes
InfrastructureFastAPIDocker

Containerizing a FastAPI App with Docker and Deploying It to Kubernetes

A step-by-step walkthrough of packaging a FastAPI Python API into a Docker container and deploying it reliably to a Kubernetes cluster. Follow a production-ready container orchestration roadmap you can apply from development through operati

Containerizing a FastAPI App with Docker and Deploying It to Kubernetes
Contents
  1. 🚀 Step 1: Containerizing Your FastAPI Application (Dockerizing)
  2. 🌐 Step 2: Understanding Kubernetes and Writing Manifests (Orchestration)
  3. 🛠️ Step 3: Deploy to a Real Cluster and Verify (Hands-On)
  4. References: Official Docs

Complete Hands-On Guide to Deploying a FastAPI API to Production with Docker and Kubernetes

"It worked perfectly locally, but as soon as I pushed it to staging I got a 500."

If you're a backend developer, you've almost certainly lived through that painful moment. We pour countless hours into business logic, but the moment we try to drop that code into the vast ecosystem of a real production environment, deployment often feels like a black box.

Even after you've built a polished API with a modern framework like FastAPI, getting that code to handle traffic and run reliably 24/7 means climbing two big mountains: containerization and orchestration.

This guide is designed so you can fully understand Docker and Kubernetes—topics you've probably only seen in theory—by actually deploying FastAPI code you wrote yourself. From junior developers to DevOps engineers, this one post should take you through the entire deployment lifecycle.


🚀 Step 1: Containerizing Your FastAPI Application (Dockerizing)

Containerization is the process of turning your application into a self-contained package. Docker is the most powerful tool for standardizing that packaging.

1. Prepare a Basic FastAPI App

First, prepare a simple FastAPI app to deploy. Put the following code in main.py.

Python
# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    """
 ID .
    """
    return {"item_id": item_id, "q": q, "message": "Successfully deployed via Docker!"}

# : when uvicorn .

Then create a requirements.txt dependency file.

TEXT
# requirements.txt
fastapi
uvicorn[standard]

2. Principles for Writing an Optimized Dockerfile

Simply using FROM python:3.10 is not an optimized approach. In production, minimizing image size and hardening security are what matter. That's why we use a multi-stage build.

Example Dockerfile:

Dockerfile
# --------------------------------------
# STAGE 1: Builder Stage
# --------------------------------------
FROM python:3.11-slim AS builder
WORKDIR /app

# when for requirements.txt
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

#
COPY . .

# --------------------------------------
# STAGE 2: Final Stage ( run )
# --------------------------------------
#
FROM python:3.11-slim
WORKDIR /app

# ( tool )
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app /app

#
EXPOSE 8000

# when when run
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

3. Local Build and Test

Now run the following commands in your terminal to build the image and verify it locally.

Bash
# 1. (my-fastapi-app:latest )
docker build -t my-fastapi-app:latest .

# 2. 8080 run
docker run -d -p 8080:8000 --name fastapi-test my-fastapi-app:latest

✅ Verify the test: Open http://localhost:8080/items/1?q=test in a browser or with curl. You should see FastAPI respond successfully.


🌐 Step 2: Understanding Kubernetes and Writing Manifests (Orchestration)

If Docker packages a single container, Kubernetes (K8s) is like an operating system that manages those containers at scale and automatically heals them.

To deploy an application on K8s, you need at least these three concepts:

  1. Deployment: Defines the desired state of your application. It maintains a declarative state such as "there should always be 3 Pods running this image."
  2. Service: Pod IPs keep changing. A Service gives those changing Pods a stable network address (Cluster IP).
  3. Ingress: Acts as the gateway for external (internet) traffic into the cluster. (For example, routing api.mycompany.com/items to a specific Service.)

💡 Example K8s Manifest YAML

For the actual deployment, write deployment.yaml and service.yaml. (Here my-fastapi-app:latest is the image name from Step 1.)

deployment.yaml:

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
  labels:
    app: fastapi
spec:
 replicas: 3 # 3 Pod settings
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi-container
 image: your-docker-registry/my-fastapi-app:latest # path required
        ports:
        - containerPort: 8000
 # settings example
        env:
        - name: ENVIRONMENT
          value: production

service.yaml:

YAML
apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  selector:
 app: fastapi # Deployment
  ports:
    - protocol: TCP
 port: 80 #
 targetPort: 8000 #
 type: ClusterIP #

🛠️ Step 3: Deploy to a Real Cluster and Verify (Hands-On)

Now it's time to apply the prepared manifests to the cluster.

1. Deployment Commands

After connecting to the cluster, run the following commands in order.

Bash
# 1. Deployment Service
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# 2. check (Pod Running whento )
kubectl get pods -l app=fastapi

💡 Troubleshooting: Pod Stuck in Pending?

If a Pod is stuck in Pending, inspect the details with: kubectl describe pod <pod-name>

🚀 Exposing the Service (Ingress / Changing Service Type)

To make it reachable from outside, set type: LoadBalancer on the Service, or—in real production—use an Ingress Controller, which is the standard approach.


📚 Summary and Key Takeaways

StepTool / ConceptPurposeKey Commands
ContainerizationDockerfilePackage the app into an isolated environmentdocker build, docker push
OrchestrationKubernetes (K8s)Automate container deployment, scaling, and managementkubectl apply -f, kubectl get pods
Service exposureService / IngressRoute external traffic to internal containerskubectl expose, Ingress Controller

By going through this process, you move beyond just writing code and fully experience the engineering cycle of deploying and operating a service in production.

References: Official Docs

The primary source for the behavior, configuration, and errors covered in this post is the official documentation below. Check it for version-specific options and exact behavior.

✦ ✦ ✦
Sources and verification

Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us

This article has no recorded human check (date and scope) yet.

Published ·

Comments

Be the first to comment.