Deploy Django on Azure Kubernetes Service (AKS)
Deploy Django on Azure Kubernetes Service: push images to Azure Container Registry, connect to Azure Database for PostgreSQL with workload identity and Key Vault secrets, expose it through Application Gateway or an ingress, and run migrations as Jobs.
Problem statement
Your organization runs on Azure and wants Django on Kubernetes rather than App Service or Container Apps, usually because several services share a cluster, or because the platform team standardizes on AKS. AKS manages the control plane, but you still decide how images are pulled, how pods reach the database and secrets without static passwords, how traffic and TLS get in, and how migrations run during releases.
- Create an AKS cluster with OIDC issuer and workload identity enabled, and attach Azure Container Registry:
az aks create ... --attach-acr acmeregistry --enable-oidc-issuer --enable-workload-identity. - Push the Django image to ACR with a commit SHA tag.
- Use Azure Database for PostgreSQL Flexible Server with private networking; store credentials in Key Vault.
- Mount Key Vault secrets with the Secrets Store CSI driver, authenticated through workload identity.
- Expose the app with Application Gateway for Containers or the AKS application routing add-on, with cert-manager or Key Vault certificates for HTTPS.
Step-by-step solution
1. Create the cluster
az group create -n acme-prod -l westeurope
az acr create -g acme-prod -n acmeregistry --sku Standard
az aks create -g acme-prod -n acme-aks \
--node-count 2 --node-vm-size Standard_D2s_v5 \
--enable-cluster-autoscaler --min-count 2 --max-count 5 \
--attach-acr acmeregistry \
--enable-oidc-issuer --enable-workload-identity \
--enable-addons azure-keyvault-secrets-provider \
--network-plugin azure
az aks get-credentials -g acme-prod -n acme-aks
--attach-acr grants the cluster's kubelet identity pull access to the registry, so no image pull secret is needed.
2. Build and push
az acr login -n acmeregistry
docker buildx build --platform linux/amd64 -t acmeregistry.azurecr.io/web:$SHA --push .
Or build in Azure with az acr build -r acmeregistry -t web:$SHA ., which avoids local architecture issues.
3. Set up workload identity and Key Vault
Create a user-assigned managed identity, grant it access to Key Vault secrets, and federate it with a Kubernetes service account:
az identity create -g acme-prod -n django-web
CLIENT_ID=$(az identity show -g acme-prod -n django-web --query clientId -o tsv)
ISSUER=$(az aks show -g acme-prod -n acme-aks --query oidcIssuerProfile.issuerUrl -o tsv)
az identity federated-credential create -g acme-prod --identity-name django-web \
--name aks-prod-web --issuer "$ISSUER" --subject system:serviceaccount:prod:web
apiVersion: v1
kind: ServiceAccount
metadata:
name: web
namespace: prod
annotations:
azure.workload.identity/client-id: "<CLIENT_ID>"
A SecretProviderClass then maps Key Vault secrets into the pod as files and, optionally, a synced Kubernetes Secret for environment variables. See Use Azure Key Vault With Django.
4. Connect to PostgreSQL
Create Azure Database for PostgreSQL Flexible Server with private access in a subnet peered with the AKS virtual network. Require TLS:
DATABASES = {"default": dj_database_url.config(conn_max_age=60, ssl_require=True)}
With Microsoft Entra authentication enabled, pods can request a short-lived access token through workload identity and use it as the password, removing database passwords entirely. Enable the server's built-in PgBouncer when many pods connect.
5. Deploy, migrate, and expose
Apply a Deployment that uses serviceAccountName: web, the label azure.workload.identity/use: "true", and the image from ACR. Run migrations as a Job with the same service account before each rollout. For ingress, use Application Gateway for Containers or the AKS application routing add-on, with cert-manager or Key Vault certificates for HTTPS. Store media in Blob Storage through django-storages[azure].
Explanation
AKS integrates Kubernetes with Azure identity. Instead of storing connection strings and keys in Kubernetes Secrets, pods present a service account token that Azure exchanges for a managed identity token through the OIDC federation. That identity can read Key Vault, write Blob Storage, and, with Entra authentication, log in to PostgreSQL. Django itself is unchanged; settings read values from environment variables or mounted files as usual.
Edge cases / notes
- Pod identity (legacy). AAD Pod Identity is deprecated; use workload identity for new clusters.
- Egress. Private clusters need outbound rules or NAT for package mirrors, Sentry, and email APIs.
- Container Apps. If you only run one Django app with workers, Azure Container Apps gives you most of this with far less to manage.
Next steps
- Compare the managed alternative in Deploy Django on Azure Container Apps.
- Set up the database with Use Azure Database for PostgreSQL With Django.
- Store files with Store Django Media in Azure Blob Storage.
FAQ
Do I need image pull secrets for ACR on AKS?
No, if you attach the registry with --attach-acr. The kubelet identity gets pull permission.
What is workload identity?
A way for Kubernetes service accounts to obtain Azure tokens through OIDC federation, so pods can access Azure services without stored secrets.
Should I use AKS or Container Apps for Django?
Container Apps for a single app with little platform work; AKS when you need full Kubernetes features or share a cluster with other services.
How do I run migrations on AKS?
As a Kubernetes Job using the new image and the same service account, completed before updating the Deployment.