Create a FastAPI Deployment
Learn how to create a Kubernetes deployment for a FastAPI service in this step-by-step tutorial. Understand the core concepts, work through a hands-on exercise, and get tips on troubleshooting common issues.
Focus: create a deployment for a fastapi service
You've built a beautiful FastAPI service, containerized it, and pushed the image to a registry. Now comes the moment of truth: getting it running in Kubernetes. But you can't just run a container like you do with Docker. If you try to run a pod directly, you'll quickly discover that pods are ephemeral — they die, get rescheduled, and vanish without a trace. That's where a Deployment comes in. A Deployment is Kubernetes' way of saying, "I want this many replicas of this app running, forever, no matter what happens." In this lesson, you'll learn how to create a deployment for a FastAPI service — the declarative, production-grade way to run your Python app on Kubernetes.
The problem this lesson solves
Imagine you're a Python developer who has just finished building a REST API with FastAPI. You've tested it locally with uvicorn, you've containerized it with Docker, and you're ready to ship. You push your image to Docker Hub and type:
kubectl run fastapi-app --image=yourname/fastapi-app:latest
It works. Your API responds to requests. But then a node in your cluster crashes, or you need to scale to handle more traffic, or you want to roll out a new version without downtime. Suddenly your single pod is gone, and you have to manually recreate it. That's the problem: pods are not self-healing. They are the smallest deployable unit in Kubernetes, but they are also ephemeral — they exist to do a job, and when they're done (or when they crash), they're gone.
A Deployment solves this by acting as a supervisor for your pods. It tells Kubernetes, "Here's the desired state: three replicas of my FastAPI app, running this image, with these environment variables." Kubernetes then works continuously to make reality match that desired state. If a pod dies, the Deployment controller creates a new one. If you want to scale up, you just change the desired replicas count. If you want to deploy a new version, you do a rolling update. The Deployment is the declarative way to manage your FastAPI service in a production cluster — it's what you'll use in virtually every real-world deployment.
Core concept / mental model
Think of a Deployment as a contract with Kubernetes. You declare your intent — "I want my FastAPI app running with these exact settings" — and Kubernetes does everything in its power to fulfill that contract. But to understand a Deployment, you need to understand its building blocks:
- Pod — the smallest unit. It runs one or more containers (in our case, one FastAPI container). It has its own IP address and can be scheduled on any node.
- ReplicaSet — the layer that ensures a specified number of pod replicas are running. If a pod dies, the ReplicaSet creates a new one. The Deployment manages the ReplicaSet.
- Deployment — the top-level controller. It manages ReplicaSets, which in turn manage pods. It adds features like rolling updates and rollbacks.
The hierarchy looks like this:
Deployment
│
└── ReplicaSet
│
├── Pod (FastAPI Container)
├── Pod (FastAPI Container)
└── Pod (FastAPI Container)
When you create a Deployment, you provide a spec that includes:
- The container image to run
- The number of replicas
- Resource limits and requests
- Environment variables (often from ConfigMaps or Secrets)
- Health checks (liveness and readiness probes)
- Update strategy (how to roll out changes)
The Deployment controller then creates a ReplicaSet, which creates the pods. If you ever change the image or any other field, the Deployment triggers a rolling update, creating a new ReplicaSet and gradually shifting traffic to the new pods.
The key mental model: you never manage pods directly. You always work with Deployments (or higher-level controllers) and let Kubernetes handle the rest. This is what makes Kubernetes resilient and scalable.
How it works step by step
Let's break down how a Deployment is created and how it behaves.
1. Define the Deployment manifest
Everything in Kubernetes is defined as YAML (or JSON). A Deployment manifest describes your desired state. Here's a minimal example for a FastAPI service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi-app
spec:
replicas: 3
selector:
matchLabels:
app: fastapi
template:
metadata:
labels:
app: fastapi
spec:
containers:
- name: fastapi-container
image: yourname/fastapi-app:latest
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
value: "postgresql://user:pass@db:5432/mydb"
Notice the selector and the template.metadata.labels. The selector must match the label in the pod template — this is how the Deployment knows which pods it governs. A common mistake is changing one without the other.
2. Apply the manifest
You submit this manifest to the Kubernetes API server using kubectl apply:
kubectl apply -f deployment.yaml
The API server validates the spec, stores it in etcd, and the Deployment controller picks it up.
3. Kubernetes creates the ReplicaSet and pods
Once the Deployment exists, the controller creates a ReplicaSet. The ReplicaSet then creates the requested number of pods. Each pod is scheduled to a healthy node in the cluster. If a node fails, the pods on it are rescheduled elsewhere.
4. Update behavior
When you modify the Deployment (e.g., change the image tag), Kubernetes performs a rolling update. It creates a new ReplicaSet with the new pod template and gradually scales up the new one while scaling down the old one. If something goes wrong, you can roll back to the previous version.
5. Scaling
To scale the app, you simply change replicas in the manifest, or use kubectl scale deployment fastapi-app --replicas=5. The Deployment ensures exactly 5 pods are running.
The whole lifecycle is declarative: you define the end state, Kubernetes figures out how to get there.
The kubectl rollout status deployment/fastapi-app command shows you the progress of a rollout. Use it in CI/CD pipelines to wait for a successful deploy.
Hands-on walkthrough
Let's put this into practice. We'll create a Deployment for a simple FastAPI service, deploy it, and test it.
Step 1: Create your FastAPI app (optional)
If you don't have an app yet, here's a minimal one. Save it as main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI on Kubernetes!"}
Step 2: Create a Deployment manifest
Create a file called fastapi-deployment.yaml with the following content:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi-app
spec:
replicas: 2
selector:
matchLabels:
app: fastapi
template:
metadata:
labels:
app: fastapi
spec:
containers:
- name: fastapi
image: python:3.10-slim
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
workingDir: /app
ports:
- containerPort: 8000
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Note: For this demo, we're using the official
python:3.10-slimimage. In production, you'd build a custom image with your code baked in. But the Deployment works the same way.
Step 3: Apply the Deployment
kubectl apply -f fastapi-deployment.yaml
Expected output:
deployment.apps/fastapi-app created
Step 4: Check the status
kubectl get deployments
kubectl get pods
You should see two pods running. To see detailed rollout status:
kubectl rollout status deployment/fastapi-app
Step 5: Scale the Deployment
Let's simulate a traffic spike:
kubectl scale deployment fastapi-app --replicas=5
Check the pods:
kubectl get pods
You'll see 5 pods. The Deployment controller immediately spins up three new ones.
Step 6: Simulate a pod failure
Delete one of the pods:
kubectl delete pod <pod-name>
Within seconds, the Deployment will create a replacement. Run kubectl get pods again — you'll see a new pod with a different name.
NAME READY STATUS RESTARTS AGE
fastapi-app-7d69f7c9d6-abc12 1/1 Running 0 10s
fastapi-app-7d69f7c9d6-def34 1/1 Running 0 2m
...
This is the magic of a Deployment: self-healing.
Step 7: Test the app
The pods are on an internal network. To access the API, you'll need a Service — that's the next lesson. But for a quick test, you can use port forwarding:
kubectl port-forward deployment/fastapi-app 8000:8000
Then in another terminal:
curl http://localhost:8000/
You'll get:
{"message": "Hello from FastAPI on Kubernetes!"}
Step 8: Update the image (rollout)
If you built a new image, update the Deployment:
kubectl set image deployment/fastapi-app fastapi=yourname/fastapi-app:v2
This triggers a rolling update. Watch it with:
kubectl rollout status deployment/fastapi-app
If something goes wrong, roll back:
kubectl rollout undo deployment/fastapi-app
Compare options / when to choose what
Now you know how to create a Deployment. But there are other ways to run containers in Kubernetes. Here's a comparison to help you choose:
| Controller | Use case | Pros | Cons |
|---|---|---|---|
| Deployment | Stateless services (FastAPI, web apps) | Rolling updates, scaling, self-healing | Not ideal for stateful workloads |
| StatefulSet | Databases, message brokers (with persistent data) | Stable network identities, persistent storage | More complex, manual scaling |
| DaemonSet | Node-level agents (e.g., log collectors) | Runs a pod on every node | Not for app scaling |
| Job | One-off tasks (batch processing) | Runs to completion | No ongoing service |
| CronJob | Scheduled tasks | Runs on a schedule | Same as Job |
For a FastAPI service, Deployment is almost always the right choice because FastAPI is stateless — it doesn't store data locally. If you need to persist data (like uploaded files), you'd use a Deployment with a persistent volume, not a StatefulSet, unless you have specific ordering needs.
Alternative approaches:
- Helm Charts — Package your Deployment along with Services, ConfigMaps, and other resources. Great for repeatable installs.
- Kustomize — Manage environment-specific overlays declaratively without templates.
- Pods directly — Never use
kubectl runfor production workloads; it's only for quick debugging.
Troubleshooting & edge cases
The Deployment didn't create pods, or they're not running? Here are common issues and fixes.
Pod stuck in Pending
This usually means no node can satisfy the pod's resource requests. Check the pod events:
kubectl describe pod <pod-name>
Look for messages like 0/3 nodes are available: insufficient cpu. Fix: reduce resources.requests in your manifest or add more nodes.
ImagePullBackOff
Kubernetes can't pull your image. Causes:
- The image name is wrong (check for typos)
- The image is private and you haven't set
imagePullSecrets - The registry is unreachable (network policies)
Debug:
kubectl describe pod <pod-name>
Look for Failed to pull image. Fix: correct the image name or add pull secrets.
CrashLoopBackOff
The container starts but keeps crashing. Common for FastAPI apps:
- Missing dependencies — if you're using a bare Python image, you need to
pip install fastapi uvicorn. In this lesson, we used thecommandto start uvicorn, but the dependencies aren't installed. - Wrong command — if you use an image that doesn't have uvicorn, the command fails.
Fix: build a proper Docker image that includes your app and dependencies. Or use pip install in a startup command (not recommended for production).
Check logs:
kubectl logs <pod-name>
Creating a Deployment via kubectl create vs kubectl apply
kubectl createcreates a resource imperatively but is not idempotent — running it again fails.kubectl applyis declarative and idempotent — you can run it as many times as you want, and it will update the resource to match the manifest.
Always use kubectl apply in production.
Validation of YAML
A simple typo (like wrong indentation) can cause an error. Use kubectl create --dry-run=client -f deployment.yaml -o yaml to validate before applying.
What you learned & what's next
You now know how to create a deployment for a FastAPI service. You've learned the core concept of declarative management, how the Deployment hierarchy works (Deployment → ReplicaSet → Pods), and you've practiced creating, scaling, updating, and recovering a Deployment. You also know the differences between Deployments and other controllers, and you can troubleshoot the most common issues.
Key mental shift: think in terms of desired state, not actions. Instead of "I will start a container," you say "I want 3 replicas of this image running." Kubernetes handles the rest.
Your FastAPI pods are now running, but they're only accessible from inside the cluster. To expose your service to users (or other services), you need a Service. That's exactly what's next in the track: Create a Service for exposing your FastAPI app. You'll learn how to make your Deployment reachable via ClusterIP, NodePort, or LoadBalancer, and how to use selectors to route traffic to the right pods.
Before you move on, make sure you:
- Understand the Deployment manifest structure
- Can create a Deployment from YAML
- Can scale and update a Deployment
- Know how to check rollout status
Then proceed to the next lesson, and soon you'll have a fully exposed, production-grade FastAPI service on Kubernetes.
Practice recap
Now it's your turn: create a Deployment for your own FastAPI app. Write a manifest with at least 2 replicas, apply it, and then practice scaling it up and down. Try deleting a pod and watch the Deployment immediately recreate it. Finally, update the image tag and observe the rolling update. Once you're comfortable, move on to the next lesson on Services.
Common mistakes
- Using
kubectl runinstead of a Deployment manifest — you lose self-healing, scaling, and declarative management. Always define a Deployment for production workloads. - Mismatching the
selectorlabels with the pod template labels — the Deployment won't manage any pods, and they'll be ignored. Keep them the same or you'll get no pods. - Forgetting resource requests and limits — the pod may get scheduled on nodes with insufficient memory and be OOM-killed. Always set at least requests and limits for CPU/memory.
- Using
latestimage tag — it makes rollouts unpredictable. Use a specific version tag (e.g.,v1.0.0) so you can roll back reliably.
Variations
- Use a Helm Chart to package your Deployment, Service, and ConfigMap into a reusable release — ideal for multi-environment installs.
- Use Kustomize to overlay environment-specific settings on the same base Deployment — great for dev/staging/prod without templating.
- Let an Ingress controller route HTTP traffic to your Deployment via a Service — but that's a later lesson; for now, use port-forward for testing.
Real-world use cases
- Deploy a FastAPI backend for a REST API with multiple replicas to handle production traffic and ensure high availability.
- Run a FastAPI-based microservice in a Kubernetes cluster with rolling updates for zero-downtime feature releases.
- Scale a FastAPI service horizontally during peak load (e.g., Black Friday) using
kubectl scaleor HPA.
Key takeaways
- A Kubernetes Deployment is the declarative way to run and manage long-running stateless services like FastAPI.
- A Deployment manages ReplicaSets, which manage Pods — never work with bare pods for production.
- The Deployment manifest defines the desired state: replicas, container image, ports, env, and health checks.
- Always use
kubectl apply(declarative) instead ofkubectl createfor reproducible, idempotent deployments. - Deployments are self-healing: if a pod dies, it's automatically replaced; scaling and rolling updates are built-in.
- To expose a FastAPI Deployment to users, you'll need a Service — the next step in this track.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.