Tutorial: Deploy Django app on AKS with Azure Database for PostgreSQL - Flexible Server

APPLIES TO: Azure Database for PostgreSQL - Flexible Server

In this quickstart, you deploy a Django application on Azure Kubernetes Service (AKS) cluster with Azure Database for PostgreSQL flexible server using the Azure CLI.

AKS is a managed Kubernetes service that lets you quickly deploy and manage clusters. Azure Database for PostgreSQL flexible server is a fully managed database service designed to provide more granular control and flexibility over database management functions and configuration settings.

Note

This quickstart assumes a basic understanding of Kubernetes concepts, Django and PostgreSQL.

Pre-requisites

If you don't have an Azure subscription, create an Azure free account before you begin.

  • Launch Azure Cloud Shell in new browser window. You can install Azure CLI on your local machine too. If you're using a local install, login with Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal.
  • Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade. This article requires the latest version of Azure CLI. If you're using Azure Cloud Shell, the latest version is already installed.

Create a resource group

An Azure resource group is a logical group in which Azure resources are deployed and managed. Let's create a resource group, django-project using the az-group-create command in the eastus location.

az group create --name django-project --location eastus

Note

The location for the resource group is where resource group metadata is stored. It is also where your resources run in Azure if you don't specify another region during resource creation.

The following example output shows the resource group created successfully:

{
  "id": "/subscriptions/<guid>/resourceGroups/django-project",
  "location": "eastus",
  "managedBy": null,
  
  "name": "django-project",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null
}

Create AKS cluster

Use the az aks create command to create an AKS cluster. The following example creates a cluster named djangoappcluster with one node. This will take several minutes to complete.

az aks create --resource-group django-project --name djangoappcluster --node-count 1 --generate-ssh-keys

After a few minutes, the command completes and returns JSON-formatted information about the cluster.

Note

When creating an AKS cluster a second resource group is automatically created to store the AKS resources. See Why are two resource groups created with AKS?

Connect to the cluster

To manage a Kubernetes cluster, you use kubectl, the Kubernetes command-line client. If you use Azure Cloud Shell, kubectl is already installed.

Note

If running Azure CLI locally , run the az aks install-cli command to install kubectl.

To configure kubectl to connect to your Kubernetes cluster, use the az aks get-credentials command. This command downloads credentials and configures the Kubernetes CLI to use them.

az aks get-credentials --resource-group django-project --name djangoappcluster

To verify the connection to your cluster, use the kubectl get command to return a list of the cluster nodes.

kubectl get nodes

The following example output shows the single node created in the previous steps. Make sure that the status of the node is Ready:

NAME                       STATUS   ROLES   AGE     VERSION
aks-nodepool1-31718369-0   Ready    agent   6m44s   v1.12.8

Create an Azure Database for PostgreSQL flexible server instance

Create an Azure Database for PostgreSQL flexible server instance with the az postgreSQL flexible-server create command. The following command creates a server using service defaults and values from your Azure CLI's local context:

az postgres flexible-server create --public-access all

The server created has the below attributes:

  • A new empty database, postgres is created when the server is first provisioned. In this quickstart we use this database.
  • Autogenerated server name, admin username, admin password, resource group name (if not already specified in local context), and in the same location as your resource group.
  • Using public-access argument allows you to create a server with public access to any client with correct username and password.
  • Since the command is using local context it creates the server in the resource group django-project and in the region eastus.

Build your Django docker image

Create a new Django application or use your existing Django project. Make sure your code is in this folder structure.

└───my-djangoapp
    └───views.py
    └───models.py
    └───forms.py
    ├───templates
          . . . . . . .
    ├───static
         . . . . . . .
└───my-django-project
    └───settings.py
    └───urls.py
    └───wsgi.py
        . . . . . . .
    └─── Dockerfile
    └─── requirements.txt
    └─── manage.py

Update ALLOWED_HOSTS in settings.py to make sure the Django application uses the external IP that gets assigned to kubernetes app.

ALLOWED_HOSTS = ['*']

Update DATABASES={ } section in the settings.py file. The code snippet below is reading the database host, username and password from the Kubernetes manifest file.

DATABASES={
   'default':{
      'ENGINE':'django.db.backends.postgresql_psycopg2',
      'NAME':os.getenv('DATABASE_NAME'),
      'USER':os.getenv('DATABASE_USER'),
      'PASSWORD':os.getenv('DATABASE_PASSWORD'),
      'HOST':os.getenv('DATABASE_HOST'),
      'PORT':'5432',
      'OPTIONS': {'sslmode': 'require'}
   }
}

Generate a requirements.txt file

Create a requirements.txt file to list out the dependencies for the Django Application. Here's an example requirements.txt file. You can use pip freeze > requirements.txt to generate a requirements.txt file for your existing application.

Django==2.2.17
postgres==3.0.0
psycopg2-binary==2.8.6
psycopg2-pool==1.1
pytz==2020.4

Create a Dockerfile

Create a new file named Dockerfile and copy the code snippet below. This Dockerfile in setting up Python 3.8 and installing all the requirements listed in requirements.txt file.

# Use the official Python image from the Docker Hub

FROM python:3.8.2

# Make a new directory to put our code in.

RUN mkdir /code

# Change the working directory.

WORKDIR /code

# Copy to code folder

COPY . /code/

# Install the requirements.

RUN pip install -r requirements.txt

# Run the application:

CMD python manage.py runserver 0.0.0.0:8000

Build your image

Make sure you're in the directory my-django-app in a terminal using the cd command. Run the following command to build your bulletin board image:

docker build --tag myblog:latest .

Deploy your image to Docker hub or Azure Container registry.

Important

If you are using Azure container registry (ACR), then run the az aks update command to attach ACR account with the AKS cluster.

az aks update -n djangoappcluster -g django-project --attach-acr <your-acr-name>

Create Kubernetes manifest file

A Kubernetes manifest file defines a desired state for the cluster, such as what container images to run. Let's create a manifest file named djangoapp.yaml and copy in the following YAML definition.

Important

Update env section below with your SERVERNAME, YOUR-DATABASE-USERNAME, YOUR-DATABASE-PASSWORD of your Azure Database for PostgreSQL flexible server instance.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: django-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: django-app
  template:
    metadata:
      labels:
        app: django-app
    spec:
      containers:
      - name: django-app
        image: [DOCKER-HUB-USER-OR-ACR-ACCOUNT]/[YOUR-IMAGE-NAME]:[TAG]
        ports:
        - containerPort: 8000
        env:
        - name: DATABASE_HOST
          value: "SERVERNAME.postgres.database.azure.com"
        - name: DATABASE_USER
          value: "YOUR-DATABASE-USERNAME"
        - name: DATABASE_PASSWORD
          value: "YOUR-DATABASE-PASSWORD"
        - name: DATABASE_NAME
          value: "postgres"
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - django-app
              topologyKey: "kubernetes.io/hostname"
---
apiVersion: v1
kind: Service
metadata:
  name: python-svc
spec:
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
  selector:
    app: django-app

Deploy Django to AKS cluster

Deploy the application using the kubectl apply command and specify the name of your YAML manifest:

kubectl apply -f djangoapp.yaml

The following example output shows the Deployments and Services created successfully:

deployment "django-app" created
service "python-svc" created

A deployment django-app allows you to describes details of your deployment such as which images to use for the app, the number of pods and pod configuration. A service python-svc is created to expose the application through an external IP.

Test the application

When the application runs, a Kubernetes service exposes the application front end to the internet. This process can take a few minutes to complete.

To monitor progress, use the kubectl get service command with the --watch argument.

kubectl get service python-svc --watch

Initially the EXTERNAL-IP for the django-app service is shown as pending.

NAME               TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
django-app   LoadBalancer   10.0.37.27   <pending>     80:30572/TCP   6s

When the EXTERNAL-IP address changes from pending to an actual public IP address, use CTRL-C to stop the kubectl watch process. The following example output shows a valid public IP address assigned to the service:

django-app  LoadBalancer   10.0.37.27   52.179.23.131   80:30572/TCP   2m

Now open a web browser to the external IP address of your service (http://<service-external-ip-address>) and view the Django application.

Note

Run database migrations

For any django application, you would need to run database migration or collect static files. You can run these django shell commands using $ kubectl exec <pod-name> -- [COMMAND]. Before running the command you need to find the pod name using kubectl get pods.

$ kubectl get pods

You see an output like this:

NAME                             READY   STATUS          RESTARTS   AGE
django-app-5d9cd6cd8-l6x4b     1/1     Running              0       2m

Once the pod name has been found you can run django database migrations with the command $ kubectl exec <pod-name> -- [COMMAND]. Note /code/ is the working directory for the project define in Dockerfile above.

$ kubectl exec django-app-5d9cd6cd8-l6x4b -- python /code/manage.py migrate

The output would look like

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  . . . . . . 

If you run into issues, run kubectl logs <pod-name> to see what exception is thrown by your application. If the application is working successfully you would see an output like this when running kubectl logs.

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
December 08, 2020 - 23:24:14
Django version 2.2.17, using settings 'django_postgres_app.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

Clean up the resources

To avoid Azure charges, you should clean up unneeded resources. When the cluster is no longer needed, use the az group delete command to remove the resource group, container service, and all related resources.

az group delete --name django-project --yes --no-wait

Note

When you delete the cluster, the Microsoft Entra service principal used by the AKS cluster is not removed. For steps on how to remove the service principal, see AKS service principal considerations and deletion. If you used a managed identity, the identity is managed by the platform and doesn't require removal.

Next steps