Deploying FastAPI Applications with Docker and Kubernetes

FastAPI is a modern, fast (high-performance) web framework for building APIs with Python based on standard Python type hints. Docker is a platform for developing, shipping, and running applications in containers, which provide a consistent environment across different systems. Kubernetes, on the other hand, is an open - source container orchestration system that automates the deployment, scaling, and management of containerized applications. Combining these technologies allows developers to efficiently deploy and manage FastAPI applications at scale. In this blog, we will explore the fundamental concepts, usage methods, common practices, and best practices for deploying FastAPI applications with Docker and Kubernetes.

Table of Contents

  1. Fundamental Concepts
  2. Deploying FastAPI with Docker
  3. Deploying Dockerized FastAPI Application with Kubernetes
  4. Common Practices
  5. Best Practices
  6. Conclusion
  7. References

Fundamental Concepts

FastAPI

FastAPI is built on top of Starlette for the web parts and Pydantic for the data parts. It uses Python type hints to validate, serialize, and deserialize data, which makes it very fast and easy to develop APIs. It also has built - in support for asynchronous programming, which can handle a large number of concurrent requests efficiently.

Docker

Docker uses containerization technology to package an application and its dependencies into a single unit called a container. Containers are isolated from each other and the host system, providing a consistent environment for the application to run. Docker images are used to create containers, and they can be stored in Docker registries such as Docker Hub or private registries.

Kubernetes

Kubernetes is a container orchestration platform that automates the deployment, scaling, and management of containerized applications. It uses concepts like pods (the smallest deployable units in Kubernetes), deployments (used to manage the creation and updating of pods), services (used to expose pods to the network), and replicasets (used to maintain a stable set of pod replicas).

Deploying FastAPI with Docker

Creating a FastAPI Application

First, let’s create a simple FastAPI application. Create a file named main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

Writing a Dockerfile

Create a file named Dockerfile in the same directory as main.py:

# Use an official Python runtime as a parent image
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install fastapi uvicorn

# Make port 8000 available to the world outside this container
EXPOSE 8000

# Run app.py when the container launches
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Building and Running the Docker Image

Build the Docker image using the following command:

docker build -t fastapi-app .

Run the Docker container:

docker run -p 8000:8000 fastapi-app

Now, you can access the FastAPI application at http://localhost:8000.

Deploying Dockerized FastAPI Application with Kubernetes

Creating Kubernetes Manifests

We need to create two main Kubernetes manifests: a deployment and a service.

Deployment Manifest (deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
      - name: fastapi-container
        image: fastapi-app
        ports:
        - containerPort: 8000

Service Manifest (service.yaml):

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

Deploying to Kubernetes

Apply the deployment and service manifests to the Kubernetes cluster:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

You can check the status of the deployment and service using the following commands:

kubectl get deployments
kubectl get services

Common Practices

Container Security

  • Use Minimal Base Images: Use minimal base images like python:3.9 - slim instead of full - fledged images to reduce the attack surface.
  • Regularly Update Dependencies: Keep the application and its dependencies up - to - date to patch security vulnerabilities.
  • Limit Container Privileges: Run containers with the least amount of privileges required.

Scaling the Application

  • Horizontal Pod Autoscaling (HPA): Use HPA to automatically scale the number of pods based on CPU utilization, memory utilization, or custom metrics. For example, you can create an HPA manifest like this:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: fastapi-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: fastapi-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

Apply the HPA manifest using kubectl apply -f hpa.yaml.

Best Practices

Monitoring and Logging

  • Prometheus and Grafana: Use Prometheus to collect metrics from the FastAPI application and Grafana to visualize the metrics. You can use exporters like prometheus - fastapi - instrumentator to expose FastAPI metrics to Prometheus.
  • Elasticsearch, Logstash, and Kibana (ELK Stack): Use the ELK stack to collect, store, and analyze application logs. You can configure the FastAPI application to send logs to Logstash.

Automated Deployment

  • Continuous Integration/Continuous Deployment (CI/CD): Use CI/CD tools like Jenkins, GitLab CI/CD, or GitHub Actions to automate the building, testing, and deployment of the FastAPI application. For example, in a GitHub Actions workflow, you can have steps to build the Docker image, push it to a registry, and deploy it to Kubernetes.
name: FastAPI Deployment

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu - latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up Docker Buildx
        uses: docker/setup - buildx - action@v1

      - name: Login to Docker Hub
        uses: docker/login - action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Build and push Docker image
        uses: docker/build - push - action@v2
        with:
          context: .
          push: true
          tags: username/fastapi - app:latest

      - name: Set up Kubernetes context
        uses: azure/k8s - set - context@v1
        with:
          method: kubeconfig
          kubeconfig: ${{ secrets.KUBE_CONFIG }}

      - name: Deploy to Kubernetes
        run: |
          kubectl apply -f deployment.yaml
          kubectl apply -f service.yaml

Conclusion

Deploying FastAPI applications with Docker and Kubernetes provides a scalable, reliable, and efficient way to manage and run applications. By understanding the fundamental concepts, following common practices, and implementing best practices, developers can ensure that their FastAPI applications are secure, performant, and easy to maintain.

References