How To Deploy FastAPI App in Your Local Kubernetes Cluster
Tags: kubernetes, fastapi, python, tutorial
Published: 2024-06-04 10:00:42

## Introduction

You are a developer and containerization holds no secrets for you, and you're looking to advance to the next level. In this tutorial, we will explore how to master container orchestration with Kubernetes. We will learn how to deploy a FastAPI app on the local Kubernetes cluster.

We will start by showing the source code of our example application with FastAPI. Next, we will create the Docker image that will be used to run the application. After that, we will move on to the step of creating the Kubernetes cluster, and we will finish the tutorial with the deployment and visualization of the results.

## Prerequisites:

You must already have Docker-Destop installed in your machine.

You need to be familiar with containerization using Docker and have a basic understanding of Kubernetes concepts.

## Creating a docker image for our FastAPI App:

### Prepare FastAPI code source:

We will use a basic example of an API to simulate the FastAPI application for our tutorial. This is an API that will get or post users.

myproject/app/main.py:

```
from typing import List

from fastapi import FastAPI, APIRouter, HTTPException
from pydantic import BaseModel, Field

app = FastAPI()


user_router = APIRouter(
    prefix='/users'
)


class User(BaseModel):
    id: int = Field(gt=0)
    name: str = Field(max_length=250)


mock_users = [
    {'id': 1, 'name': "Jean Ton"},
    {'id': 2, 'name': "Jean Toto"}
]


@user_router.get('/')
async def get_users() -> List[User]:
    users = [User(**user) for user in mock_users]
    return users


@user_router.get('/{user_id}')
async def get_user(user_id: int):
    user = next((User(**user) for user in mock_users if user['id'] == user_id), None)
    if user is None:
        raise HTTPException(status_code=404, detail='User Not Found')

    return user


@user_router.post('/', response_model=User, status_code=201)
async def add_user(user: User) -> User:

    if any(existing_user['id'] == user.id for existing_user in mock_users):
        raise HTTPException(status_code=400, detail="User already exists")

    mock_users.append(user.dict())

    return user


app.include_router(user_router)

```

myproject/requirements.txt:

```
fastapi==0.111.0

```

### Build and push the docker image:

The next step is to create the docker image to be used to run FastAPI app

#### Build the image:

We will use the following Dockerfile:

myproject/Dockerfile:

```
FROM python:3.9

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

EXPOSE 80

CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```

Run this command to create the image:

```
docker build . -t kubernetes-fastapi-app-img

```
#### Push the image to a private registry:

When deploying a Kubernetes application, you typically specify the container image that Kubernetes should pull from a container registry. However, if you want to use a local image (one that is not in a registry), you can use a few methods.

These are some methods to use local images in Kubernetes:

1. Using Minikube or Kind (Kubernetes in Docker):

Both Minikube and Kind allow you to use local Docker images directly. You can load the image into the Minikube or Kind environment.

2. Using a Private Registry:

If you are not using Minikube or Kind, you can set up a local Docker registry to which you push your image, and then configure Kubernetes to pull from this registry.

For this tutorial, we will use a private registry that we will run locally using the follwing command:

```
docker run -d -p 5000:5000 --name registry registry:2

```

Then we will tag the image:

```
docker tag kubernetes-fastapi-app-img:latest localhost:5000/kubernetes-fastapi-app-img:latest
```

Push the image to your local registry:

```
docker push localhost:5000/kubernetes-fastapi-app-img:latest
```

### Create Kubernetes cluser:

Now that our FastAPI docker image is ready in the registry, let's install the Kubernetes cluser:

Open your Docker-desktop, go to Settings >> Kubernetes, then select the option 'Enable Kubernetes'. This will install all the necessary ressources for functional Kubernetes Cluser.

![How to enable Kubernetes in Docker-desktop](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkox27a42yyghc2li74x.png)

To check if Kubernetes is installed and is running, open your terminal and type the command `kubectl`. Everything is fine if the output starts with `kubectl controls the Kubernetes cluster manager`.

### Deployment file:

The next step is to deploy our image in Kubernetes. For this, we need to create a YAML file that will contain the deployment configuration.:

myproject/deploy/deploy.yaml

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
  labels:
    app: fastapi
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi
        image: localhost:5000/kubernetes-fastapi-app-img
        ports:
        - containerPort: 80
        env:
        - name: ENVIRONMENT
          value: "testing"

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

```
This Kubernetes YAML file defines a Deployment resource for deploying our FastAPI application. Below is a brief explanation of key parts of the file:

- Deployment Name: fastapi-deployment

- Labels: app: fastapi for both the deployment and its pods.

- Replicas: 1 instance (pods) of the FastAPI application.

- Container Image: The container uses an image from a local registry (localhost:5000/kubernetes-fastapi-app-img).

- Container Port: The container listens on port 80.

### Apply the deployment configuation to Kubernetes cluster:

Firstly, make sure that the current context is set to `docker-desktop` using:

```
kubectl config current-context
```

If that's not the case, you can switch to `docker-desktop` using the following command:

```
kubectl config use-context docker-desktop
```

Now, we are ready to apply our deployment file:

```
kubectl apply -f deploy\deploy.yaml
```

![Apply deployment output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eco7amdvi1vko6t4stad.png)


Use the command bellow to see the status of the created pod:

```
kubectl get pods
```
![Getting pods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tc905eukhgkv6rpxnv0z.png)


We can show logs of our created pod:

```
kubectl logs fastapi-deployment-8fc7dd7d-z45k4
```


![Pod logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkaner6xb5qm8tfb2ggm.png)

Our API swagger is accessible locally via [http://localhost/docs](http://localhost/docs)


![FastAPI API Swagger](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv68445ngqkgj26x2dvp.png)

## Conclusion

This tutorial is primarily aimed at developers who want to deploy their applications on Kubernetes, but it can also be useful for those who want to deploy their applications on remote Kubernetes clusters, such as those on Azure or AWS.

I would be delighted to see your comments or answer your questions.