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

Sponsored

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-slim image. 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 run for 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 the command to 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 create creates a resource imperatively but is not idempotent — running it again fails.
  • kubectl apply is 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 run instead of a Deployment manifest — you lose self-healing, scaling, and declarative management. Always define a Deployment for production workloads.
  • Mismatching the selector labels 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 latest image tag — it makes rollouts unpredictable. Use a specific version tag (e.g., v1.0.0) so you can roll back reliably.

Variations

  1. Use a Helm Chart to package your Deployment, Service, and ConfigMap into a reusable release — ideal for multi-environment installs.
  2. Use Kustomize to overlay environment-specific settings on the same base Deployment — great for dev/staging/prod without templating.
  3. 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 scale or 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 of kubectl create for 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.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.