Deploying a Django Rest Framework (DRF) application to Kubernetes

Understand how to take your Django Rest Framework application from development to production, leveraging Kubernetes to manage and scale the application efficiently.

10 minutes reading time

Written by

Civo Team
Civo Team

Marketing Team @ Civo

This tutorial is going to provide you with a comprehensive guide on deploying a Django Rest Framework (DRF) application to Kubernetes. In this tutorial, you'll be taken through a step-by-step tutorial covering the entire process, starting from setting up the development environment, building the DRF application, containerizing it, and finally deploying it to Kubernetes.

By the end of this tutorial, you'll have a clear understanding of how to take your Django Rest Framework application from development to production, leveraging Kubernetes to manage and scale the application efficiently.

Let's get started and dive into the world of deploying DRF applications on Kubernetes!

Overview of the DRF

Django Rest Framework (DRF) is a robust and widely-used web framework, built on Django, the renowned Python web development framework. DRF specializes in streamlining the development of RESTful APIs (Application Programming Interfaces) for web applications. By leveraging DRF, developers can efficiently handle data serialization, authentication, and various other features essential for modern web development. With its user-friendly design and extensive toolkit, DRF empowers developers to create high-performance APIs with ease and flexibility.

Prerequisites

Before getting started, there are some prerequisites you’ll need to have in place:

Setting up the development environment

Follow these steps to set up the development environment:

Step 1: Open a terminal or command prompt.

Step 2: Verify if you have virtualenv installed by running the following command:

pip install virtualenv

Step 3: Create and activate a virtual environment:

virtualenv venv

On macOS/Linux:

source venv/bin/activate

On Windows:

venv\Scripts\activate

Step 4: Create a project directory for the Django Rest Framework application:

mkdir drf_kubernetes
cd drf_kubernetes

Step 5: Install the required packages.

Create a requirements.txt file and add the following contents:

djangorestframework==3.13.1
Django==4.1.2

Run the command below to install the packages:

pip install -r requirements.txt

Step 6: Create a Django Project.

With the virtual environment activated, create the Django project. In this case, we'll name the project drf_kubernetes:

django-admin startproject drf_kubernetes .

Note: Take note of the . after the django-admin startproject drf_kubernetes command.

Building the DRF application

With the development environment set up and the project created, let's proceed to build the DRF application. We will create a REST API for a sample Movie database model, which will involve implementing all CRUD operations.

Step 1: Create the Movie App

Run the following command to create a Django app named Movie:

django-admin startapp Movie

Step 2: Edit the settings.py file:

Add restframework and the created app Movie to the INSTALLEDAPPS in the settings.py file:

INSTALLED_APPS = [
# Other installed apps
'rest_framework', # Add this line
'Movie.apps.MovieConfig', # Add this line
]

Step 3: Update the urls.py in the drf_kubernetes directory to include the Movie app URLs:

from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('Movie.urls')),
]

Step 4: Add the following code to the models.py file inside the Movie app directory:

from django.db import models
class Movie(models.Model):
class Genre(models.TextChoices):
ACTION = 'action'
FANTASY = 'fantasy'
ADVENTURE = 'adventure'
ROMANCE = 'romance'
SCI_FI = 'sci-fi'
Anime = 'anime'
title = models.CharField(max_length=100)
producer = models.CharField(max_length=50)
genre = models.CharField(max_length=20, choices=Genre.choices)
release_date = models.DateField()
def __str__(self):
return self.title

The Movie class represents the database model for a movie in our API. It includes columns for the movie's title, producer, genre, and release date.

Step 5: Create a serializers.py file inside the Movie app directory with the following code:

from rest_framework import serializers
from .models import Movie
class MovieSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
class Meta:
model = Movie
fields = [
'id',
'title',
'producer',
'genre',
'release_date',
]

The MovieSerializer defines a serializer that allows us to convert the Movie model data into Python data types for API requests and responses.

Step 6: Update the views.py file in the Movie app with the following code:

from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from .models import Movie
from .serializers import MovieSerializer
class MovieListCreate(ListCreateAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
class MovieRetrieveUpdateDestroy(RetrieveUpdateDestroyAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer

The MovieListCreate class defines the views for creating and getting all movies, while the MovieRetrieveUpdateDestroy class handles retrieving, updating, and deleting movies.

Step 7: Create a urls.py file inside the Movie app with the following code:

from django.urls import path
from . import views
urlpatterns = [
path('movies/', views.MovieListCreate.as_view(), name='movie-list-create'),
path('movies//', views.MovieRetrieveUpdateDestroy.as_view(), name='movie-retrieve-update-destroy'),
]

Step 8: Run migrations:

To create the necessary database tables, run the following commands in your terminal:

python manage.py makemigrations
python manage.py migrate

Step 9: Start the development server to test the Django Rest Framework application:

python manage.py runserver

Now the Django Rest Framework application is up and running! You can access the API endpoints for the `Movie` model at the following URLs:

  • List and Create: http://localhost:8000/movies/
  • Retrieve, Update, and Destroy: http://localhost:8000/movies//

Containerization of Django Rest Framework (DRF) with Docker

Before proceeding with containerizing the Django Rest Framework application, some changes need to be made.

Step 1: Update SECRET_KEY and DEBUG handling:

In the settings.py file, modify the SECRET_KEY and DEBUG settings to use environment variables. This helps keep sensitive information separate from the codebase and enhances security. Use the following code:

import os
SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = bool(os.getenv('DEBUG', 'True'))

Step 2: Update the database settings in the settings.py file to use PostgreSQL:

Replace the existing DATABASES section with the following:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'USER': os.getenv('POSTGRES_USER'),
'NAME': os.getenv('POSTGRES_NAME'),
'PASSWORD': os.getenv('POSTGRES_PASSWORD'),
'HOST': os.getenv('POSTGRES_HOST'),
'PORT': os.getenv('POSTGRES_PORT'),
}
}

Step 3: Update allowed hosts:

In the settings.py file, update the ALLOWED_HOSTS setting to allow all hosts:

ALLOWED_HOSTS = ['*']

Step 4: Enable static files:

Static files need to be served correctly in our containerized environment. In the settings.py file, add the following code to set the STATIC_ROOT:

STATIC_ROOT=/static/

Additionally, update the urls.py file in the drf_kubernetes directory to correctly handle static file serving:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.contrib.staticfiles.urls import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('Movie.urls'))
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # add this

Step 5: Update the requirements.txt file with the following content:

djangorestframework==3.13.1
Django==4.1.2
gunicorn==20.1.0
psycopg2-binary==2.9.3

The psycopg2-binary package has been added to enable the PostgreSQL database connection.
The gunicorn package has been added as a production-ready WSGI server, which will serve the Django application efficiently.

Step 6: Create a file named script.sh in the project directory and add the following content:

#!/bin/sh
# Change to the app directory
cd /app
# Apply database migrations
echo "Applying database migrations"
python manage.py makemigrations
python manage.py migrate --noinput
# Collect static files
echo "Collecting static files"
python manage.py collectstatic --noinput
# Start the server using gunicorn
echo "Starting the server"
gunicorn drf_kubernetes.wsgi:application --bind 0.0.0.0:8000

This script will be executed when the container starts and will take care of necessary setup tasks.

Docker configuration and deployment

Now, let's proceed with containerizing the application:

Step 1: Ensure that Docker is installed on your system. If you don't have it installed, refer to the Docker installation guide and install Docker.

Step 2: Create a Dockerfile in the project directory and include the following contents:

FROM python:3.9-alpine
WORKDIR /app
COPY ./requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN chmod +x /app/script.sh
CMD ["./script.sh"]

The Dockerfile starts with the base image of Python 3.9-alpine.
WORKDIR command: Sets the working directory inside the container as /app, which will be the root directory for the application.
COPY ./requirements.txt .: Copies the requirements.txt file from the local directory to the container's /app directory.
RUN pip install -r requirements.txt: Installs the Python dependencies specified in requirements.txt using pip.
The second COPY command: Copies the entire project directory (including the application code) into the container's /app directory.
RUN chmod +x /app/script.sh: Gives execution permissions to the script.sh script.
CMD ["./script.sh"]: Specifies the command to run when the container starts. In this case, it executes the script.sh script, which applies database migrations, collects static files, and starts the server using gunicorn.

Step 3: Build the Docker image by running the following command in the terminal: Replace your-username and your-repository-name with the appropriate values:

docker build -t /:drf-app .

-t specifies the tag for the image.
It builds the Docker image with the name drf-app (you can change this name if desired).
. points to the current directory containing the Dockerfile.

Step 4: Once the image is built, push it to a Docker repository. Here are the steps to push the image to Docker Hub:

  1. Sign up for a Docker Hub account.
  2. Log in to the Docker repository using the following command and provide your credentials when prompted: docker login
  3. Push the repository to the container registry using the following command: docker push /:drf-app
    Replace and with your Docker Hub username and the repository name where you want to push the image.

Step 5: Finally, before proceeding with deployment, you need to provision a PostgreSQL database on Civo:

  1. Sign in to your Civo account.
  2. Create a new PostgreSQL instance with the desired specifications, such as CPU and RAM.
  3. Make a note of the connection details, including the hostname, port, database name, user, and password.

Deploying the DRF application on Civo

To successfully deploy your Django Rest Framework (DRF) application on a managed Kubernetes cluster using Civo, you can follow these steps:

Step 1: Begin by making sure you have completed the initial setup, including launching a cluster on Civo, downloading the cluster's kubeconfig credential, and installing the Kubernetes command-line tool, kubectl on your local machine.

Step 2: Configure your local kubectl with the cluster credentials you've downloaded by executing the following commands:

export KUBECONFIG=/path/to/downloaded/kubeconfig/credential

Note: Replace /path/to/downloaded/kubeconfig/credential with the actual path to your downloaded kubeconfig cluster credential.

Step 3: In your project directory, create a .env file with the necessary environment variables:

POSTGRES_HOST=
POSTGRES_PORT=
POSTGRES_NAME=
POSTGRES_USER=
POSTGRES_PASSWORD=
SECRET_KEY=

Note: Replace the placeholders with actual details from your managed PostgreSQL database on Civo and your Django SECRET_KEY.

Step 4: Create a Kubernetes secret using the command below to securely manage the secrets:

kubectl create secret generic --from-env-file .env drf-app-secret

Step 5: Create a drf.yaml file that outlines both the service and deployment manifests required for deploying the DRF application:

apiVersion: v1
kind: Service
metadata:
name: drf-app
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 8000
selector:
app: drf-app
type: api
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: drf-app
spec:
replicas: 2
selector:
matchLabels:
app: drf
type: api
template:
metadata:
labels:
app: drf-app
type: api
spec:
containers:
- name: drf-app
image: your-username/your-repository-name:drf-app
imagePullPolicy: Always
ports:
- containerPort: 8000
envFrom:
- secretRef:
name: drf-app-secret
env:
- name: DEBUG
value: "False"

The drf.yaml file contains Kubernetes manifest definitions that outline how your Django Rest Framework (DRF) application should be deployed and managed within a Kubernetes cluster. It consists of two main parts:

  • Service Manifest: This section defines a Kubernetes Service, which acts to enable network communication to your application. Specifically, it configures a LoadBalancer type service that listens on port 80 and directs traffic to port 8000 on the application pods. The service is associated with pods that have the labelsapp: drf-appand type: api.
  • Deployment Manifest: This section specifies a Kubernetes Deployment, which orchestrates the management of your application's pods. It sets up two replicas of your application to ensure high availability. The deployment is linked to pods labeled with app: drf and type: api.

Inside the deployment's template, the containers section defines the main application container named drf-app. It pulls the application image from a specified container registry (e.g., your-username/your-repository-name:drf-app). The container listens on port 8000 and is configured with environment variables obtained from the secret drf-app-secret`.

The env section also includes an environment variable named DEBUG set to "False", which indicates that the DRF application is not in debugging mode.

Step 6: Deploying with a Private Repository:

If your repository is private, you need to create an image pull secret to allow Kubernetes to access the private images. Use the following command to create the necessary image pull secret:

kubectl create secret docker-registry registry-secret --docker-server=https://index.docker.io/v1/ --docker-username= --docker-password= --docker-email=

Replace your-nameyour-password and your-email with your actual Docker username, email and password.

Next, modify the drf.yaml file to include the newly created image pull secret. Add the imagePullSecrets field under the deployment spec.template.spec section:

spec:
containers:
- name: drf-app
image: your-username/your-repository-name:drf-app
imagePullPolicy: Always
ports:
- containerPort: 8000
envFrom:
- secretRef:
name: drf-app-secret
env:
- name: DEBUG
value: "False"
imagePullSecrets:
- name: registry-secret

By adding the image pull secret, Kubernetes will be able to retrieve images from your private repository.

Step 7: Apply the defined resources to your cluster using the following command:

kubectl apply -f drf.yaml

Step 8: Retrieve the external IP assigned to the DRF application service using:

kubectl get service drf-app

With the external IP in hand, you can access the Django Rest Framework Application Movie APIs through your browser:

List and Create:

http://(external-ip-address)/movies

List and Create

Retrieve, update, and destroy:

http://(external-ip-address)/movies

Retrieve, Update, and Destroy

By following these steps, you'll have your DRF application up and running on Civo's managed Kubernetes cluster.

Summary

This tutorial provided you with a comprehensive guide to deploying a Django Rest Framework (DRF) application to Kubernetes. Throughout the tutorial, we have covered all the necessary steps, from setting up the development environment to containerizing the application and deploying it to a Kubernetes Cluster on Civo.

Further resources

To further enhance your skills and expand your knowledge, consider exploring the following resources:

Civo Team
Civo Team

Marketing Team @ Civo

Civo is the Sovereign Cloud and AI platform designed to help developers and enterprises build without limits. We bridge the gap between the openness of the public cloud and the rigorous security of private environments, delivering full cloud parity across every deployment. As a team, we are dedicated to providing scalable compute, lightning-fast Kubernetes, and managed services that are ready in minutes. Through CivoStack Enterprise and our FlexCore appliance, we empower organizations to maintain total data sovereignty on their own hardware.

Our mission is to make the cloud faster, simpler, and fairer. By providing enterprise-grade NVIDIA GPUs and streamlined model management, we ensure that high-performance AI and machine learning are accessible to everyone. Built for transparency and performance, the Civo Team is here to give you total control over your infrastructure, your data, and your spend.

View author profile