Deploy Django on Amazon EKS

Deploy Django on Amazon EKS: build images in ECR, expose the app through an ALB with the AWS Load Balancer Controller and ACM certificates, connect to RDS, grant AWS access with Pod Identity, sync secrets, and run migrations as Jobs.

Problem statement

Your organisation standardises on Kubernetes and AWS, and the Django app needs to run on Amazon EKS alongside other services. EKS gives you a managed control plane; you still need to connect the AWS pieces correctly: images in ECR, an Application Load Balancer created from Kubernetes Ingress resources, certificates from ACM, RDS PostgreSQL in private subnets, IAM permissions for S3 and SES without access keys, and secrets that do not live in Git.

Django on EKSECR imagetagged by commitPods on EKSGunicorn DeploymentALB controllerIngress to ALB + ACMRDS + Pod IdentityDB and AWS accessEKS runs pods; AWS controllers create the load balancer and grant IAM access.
  1. Create the cluster with eksctl (or Terraform), using managed node groups or Fargate profiles, in private subnets.
  2. Install the AWS Load Balancer Controller; create an Ingress with ingressClassName: alb and an ACM certificate ARN.
  3. Run RDS PostgreSQL in private subnets; allow the node or pod security group on port 5432.
  4. Use EKS Pod Identity (or IRSA) so pods get IAM roles for S3, SES, and Secrets Manager.
  5. Sync secrets from Secrets Manager with External Secrets Operator or the Secrets Store CSI driver.
  6. Run migrate as a Job before each rollout; set readiness probes and graceful shutdown.

Step-by-step solution

1. Cluster and image registry

eksctl create cluster --name django-prod --region eu-west-1 --version 1.31 \
  --nodegroup-name web --node-type t3.large --nodes 2 --nodes-min 2 --nodes-max 5 --node-private-networking
aws ecr create-repository --repository-name myapp

Build and push images tagged with the commit SHA. Enable the EKS Pod Identity Agent add-on for IAM access.

2. Load balancer and HTTPS

Install the AWS Load Balancer Controller (Helm chart eks/aws-load-balancer-controller) with its IAM role. Then:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: app
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-west-1:123456789012:certificate/abc
    alb.ingress.kubernetes.io/healthcheck-path: /health/
spec:
  ingressClassName: alb
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend: { service: { name: web, port: { number: 80 } } }

target-type: ip sends traffic straight to pod IPs. The ALB terminates TLS, so Django needs SECURE_PROXY_SSL_HEADER, and the health check path must pass ALLOWED_HOSTS (send no Host requirement on /health/, or allow pod IPs for that path through middleware).

Kubernetes object to AWS resourceCreates or usesGives DjangoIngress (alb class)ALB + ACM certificate✓HTTPS entry pointServiceAccount + Pod IdentityIAM role✓S3, SES without keysExternalSecretSecrets Manager✓SECRET_KEY, DB passwordService (ClusterIP)ALB target group (ip)✓traffic to podsControllers translate Kubernetes resources into AWS resourcesdjango-deployment.com
Install each controller once per cluster; apps then only declare Kubernetes objects.

3. RDS connectivity

Create RDS PostgreSQL (Multi-AZ for production) in the cluster VPC's private subnets. Allow inbound 5432 from the node security group, or use Security Groups for Pods to allow only Django pods. Require TLS with sslmode=require in DATABASE_URL. For many replicas, consider RDS Proxy to cap connections.

4. IAM for pods

aws eks create-pod-identity-association --cluster-name django-prod --namespace app \
  --service-account django --role-arn arn:aws:iam::123456789012:role/django-app

The role's policy grants the bucket, SES identity, and secrets the app needs. boto3 in the pod picks up credentials automatically; remove any AWS_ACCESS_KEY_ID settings.

5. Secrets

External Secrets Operator syncs Secrets Manager values into Kubernetes Secrets:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata: { name: django-env, namespace: app }
spec:
  secretStoreRef: { name: aws-secrets, kind: ClusterSecretStore }
  target: { name: django-env }
  dataFrom: [{ extract: { key: prod/django } }]

Mount it with envFrom in the Deployment.

6. Migrations and rollout

Run a Job using the same image and service account, wait for completion, then update the Deployment image. Set terminationGracePeriodSeconds above Gunicorn's graceful timeout and the ALB deregistration delay so in-flight requests finish.

EKS specifics to get rightNodes and RDS in private subnetsonly the ALB is publicALB controller with ACM certssl-redirect, health check pathPod Identity or IRSAno access keys in envSecrets synced from Secrets Managernot committed to GitMigration Job before rolloutgraceful shutdown configuredEach item replaces a manual or insecure shortcutdjango-deployment.com
Codify the cluster and add-ons in Terraform so environments match.

Verification check: kubectl get ingress -n app shows an ALB address, the ALB target group lists healthy pod IPs, https://example.com serves the ACM certificate, and aws sts get-caller-identity run inside a pod returns the app role.

Explanation

EKS provides upstream Kubernetes with an AWS-managed control plane, and AWS integration happens through controllers and add-ons running in the cluster. The AWS Load Balancer Controller watches Ingress objects and creates ALBs and target groups; Pod Identity injects role credentials into pods; External Secrets reads Secrets Manager. Django itself is a standard containerised WSGI app; the deployment work is wiring these integrations so that the app reaches its database and AWS services securely and receives traffic only when ready.

Edge cases / notes

  • Fargate profiles remove node management but do not support DaemonSets and some add-ons; check compatibility.
  • Celery runs as separate Deployments; Beat as a single replica or a leader-elected scheduler.
  • Cost. EKS charges per cluster hour plus nodes and ALBs; for a single app, ECS Fargate is usually cheaper and simpler.
  • Upgrades. EKS versions have a support window; plan cluster upgrades yearly.

Next steps

FAQ

Should I use EKS or ECS for Django?

ECS is simpler for a single app. EKS fits when your organisation already runs Kubernetes or needs its ecosystem.

How do Django pods get AWS permissions?

Through EKS Pod Identity or IRSA, which map a Kubernetes service account to an IAM role.

How is HTTPS handled on EKS?

The AWS Load Balancer Controller creates an ALB with an ACM certificate from an Ingress resource.

Where should migrations run?

In a Kubernetes Job before updating the Deployment.

Keep going