DEV Community

Cover image for Deploying a FastAPI app to Kubernetes with health probes
Sergio Peris
Sergio Peris

Posted on • Originally published at sertxu.dev

Deploying a FastAPI app to Kubernetes with health probes

This week, I was updating the image of a FastAPI app in our Kubernetes cluster, but I took the whole app down because the process failed due to an incompatible dependency with our server. The updated pod was unable to start, but we didn't have health checks in place, so the deployment continued to update the other replicas, taking down all app instances.

In this tutorial, I will explain how to add a health check to your FastAPI app to ensure the deployment doesn't continue updating the pods if they fail.

Adding a health endpoint to your FastAPI app

Kubernetes requires two endpoints, liveness and readiness. What's the difference between them?

  • Liveness endpoint: Should return a 200 OK as long as the app is running.
  • Readiness endpoint: Should return a 200 OK when the app is ready to handle traffic.

If your app takes some time from boot since it's ready to start handling traffic, it makes sense to have two different endpoints. This also prevents Kubernetes from killing the updated pod while it's still booting.

For this tutorial, we will create only one endpoint at /health. This is a minimal FastAPI app:

from fastapi import FastAPI

app = FastAPI()

@app.get("/health")
def health_check():
    return {"status": "OK"}
Enter fullscreen mode Exit fullscreen mode

Containerizing the app

To run this app in Kubernetes, you should create a Docker image. This is a basic image:

FROM python:3.13-slim

WORKDIR /app

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

COPY main.py .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--log-level", "warning", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

The requirements.txt file only needs fastapi and uvicorn for this example.

Then we build the Docker image, and push it to a registry your Kubernetes cluster can access, like Docker Hub or a private registry.

docker build -t fastapi-health-app:latest .
Enter fullscreen mode Exit fullscreen mode

Kubernetes deployment manifest

To deploy the app in your Kubernetes cluster, you need to create a deployment manifest.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
      - name: fastapi-app
        image: fastapi-health-app:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 8000

        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 10
          timeoutSeconds: 1
          failureThreshold: 3

        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 1
Enter fullscreen mode Exit fullscreen mode

With this configuration, both liveness and rediness probes use HTTP GET requests to the path /health on port 8000.

The initialDelaySeconds option gives the app time to start before the first health check.

For liveness, the periodSeconds option sets the check interval to 10 seconds.
The failureThreshold option will restart the pod after 3 consecutive failed checks.

For readiness, the periodSeconds option sets the check interval to 5 seconds.
The failureThreshold option will mark the pod as not ready and remove it from service load balancers after one failed check.

To expose the app you need to create a service. Here's a simple service manifest:

apiVersion: v1
kind: Service
metadata:
  name: fastapi-app-service
spec:
  selector:
    app: fastapi-app
  ports:
  - port: 80
    targetPort: 8000
  type: ClusterIP
Enter fullscreen mode Exit fullscreen mode

Applying the configuration

Once you've created both manifests, you should deploy them to your cluster.

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Enter fullscreen mode Exit fullscreen mode

Wait a few seconds for the pods to start, then you can check the status with:

kubectl get pods
Enter fullscreen mode Exit fullscreen mode
NAME                                 READY   STATUS    RESTARTS   AGE
fastapi-app-86b64cbbd5-9qkvd         1/1     Running   0          5m
Enter fullscreen mode Exit fullscreen mode

You should see the pod in a Running state with READY 1/1 once the readiness probe passes, meaning your app is ready to start receiving requests.

Verifying the probes work

To confirm the probes are working, you can check the pod details with:

kubectl describe pod [pod-name]
Enter fullscreen mode Exit fullscreen mode

Look for the Liveness and Readiness sections in the output.

...
Liveness:  http-get http://:8000/health delay=5s timeout=1s period=10s #success=1 #failure=3
Readiness: http-get http://:8000/health delay=5s timeout=1s period=5s #success=1 #failure=1
...
Enter fullscreen mode Exit fullscreen mode

If you port forward the service you can also test the endpoint locally:

kubectl port-forward svc/fastapi-app-service 8000:8000
Enter fullscreen mode Exit fullscreen mode

You can use curl to see the endpoint response:

curl localhost:8000/health
Enter fullscreen mode Exit fullscreen mode

In closing

Adding health endpoints to a FastAPI app takes only a few lines of code, and configuring Kubernetes probes is fairly easy.

The key difference is tunning the liveness and readiness probe options to your app needs.

If you want to extend this setup, you could add a different endpoint for readiness probe that verifies a database connection or a cache is available before marking the app as ready.

Top comments (0)