Apr 28th, 2021

Ultimate Guide to Securely Deploy Django at Scale on AWS ECS [Part 3]

#DjangoAWSDeployment

#AWSElasticContainerService

#AmazonElasticContainerRegistry

NOTE: This is the third part of a blog series.

Part 1: Coding the XKCD Django App

Part 2: AWS: Configuring RDS, Parameter Store, ElastiCache

Part 3: AWS: Deploying XKCD App to Elastic Container Service

Overview

If you’ve successfully followed the Part 2 of this blog series you should have a working Django application connected to RDS, ParameterStore and/or ElastiCache. In this final blog post of the series, we will be uploading the applications docker image to Elastic Container Registry and deploying that image to Elastic Container Service under an Application Load Balancer. When we successfully deploy our application and make sure everything is working properly, we will tighten our security by configuring the inbound and outbound rules of the security groups we created.

Index

Part 1: Coding the XKCD Django App

Coding the XKCD Django App

  1. Creating and activating a virtual environment
  2. Installing Django
  3. Creating database models
  4. Adding models to Django admin page
  5. Creating the homepage view
  6. Adding homepage view to URLs
  7. Creating homepage.html
  8. Creating requirements.txt file
  9. Dockerizing our Django App
    1. Testing the Docker Image

Part 2: AWS: Configuring RDS, Parameter Store, ElastiCache

Configuring AWS

  1. AWS RDS - Relational Database Service
    1. Configuring RDS Security Group
    2. Creating a Postgresql Database on RDS
    3. Updating Django settings to use the PostgreSQL Database Backend
      1. Install the PostgreSQL library
      2. Update the settings.py
  2. AWS Systems Manager Parameter Store
    1. Adding our secrets to Parameter Store
    2. Configuring Django App to use AWS Parameter Store
      1. Install AWS SDK for Python: boto3
      2. Update the settings.py file
    3. Migrating Django models to RDS instance
    4. Build & run the docker image with the aws credentials
    5. Creating Parameter Store IAM Role
    6. Creating a super user
  3. ElastiCache Redis
    1. Creating the Security Group: XKCDAppElastiCacheSecurityGroup
    2. Creating the ElastiCache Redis Instance
    3. Adding ElastiCache endpoint to Parameter Store
    4. Installing django-redis package
    5. Updating Django settings to use Redis as Session Storage

Part 3: AWS: Deploying XKCD App to Elastic Container Service

  1. Elastic Container Registry
    1. Uploading XKCD Apps Docker Image to ECR
  2. Elastic Load Balancing
    1. ELB Security Group Creation
    2. ELB Creation
      1. Step 1: Configure Load Balancer
      2. Step 2: Security Settings
      3. Step 3: Security Groups
      4. Step 4: Routing: Target Group Creation
      5. Step 5: Registering Targets to Target Group
      6. Step 6: Review
      7. Step 7: Forward traffic from port 80 to port 8000
  3. Elastic Container Service
    1. Creating an ECS Task Execution Role: XKCDAppECSTaskExecutionRole
    2. Creating ECS security group: XKCDAppECSSecurityGroup
    3. Creating Task Definition: XKCDAppTaskDefinition
      1. Adding a container to XKCDAppTaskDefinition
    4. Creating Cluster Service
      1. Step 1: Configure Service
      2. Step 2: Configure Network
      3. Step 3: Set Auto Scaling
      4. Step 4: Review
    5. Load Testing our App with Hey
    6. Creating Auto Scaling for XKCDAppClusterService
      1. Testing the Auto Scaling Policy
  4. Updating Security Groups
    1. Updating XKCDAppElasticLoadBalancerSecurityGroup
    2. Updating XKCDAppECSSecurityGroup
    3. Updating XKCDAppElastiCacheSecurityGroup
    4. Updating XKCDAppRDSSecurityGroup

 

4. Elastic Container Registry

Go to Repositories under Elastic Container Registry and click on the Create Repository button. Give your ECR repository a name and click create.

image shows creation of Elastic Container Registry

Elastic Container Registry Creation

4.1 Uploading XKCD Apps Docker Image to ECR

Go to detail page of your repository and click on the View Push Commands on the upper right. This will give you login, build, tag and push commands specific to your repository.

# get credentials to ECR Repo
aws ecr get-login-password --region eu-west-2 | docker login --username AWS --password-stdin 12345678912.dkr.ecr.eu-west-2.amazonaws.com

#build your image
docker build -t xckdapp .

# tag it as the latest
docker tag xckdapp:latest 12345678912.dkr.ecr.eu-west-2.amazonaws.com/xckdapp:latest

# push to ECR
docker push 12345678912.dkr.ecr.eu-west-2.amazonaws.com/xckdapp:latest

5. Elastic Load Balancing

We are going to access to our Elastic Container Service container instances through a AWS Elastic Load Balancer. We are going to create the ELB first in order to add it to Elastic Container Service upon creation.

5.1 ELB Security Group Creation

Go to Security Groups under VPC and create one.

 image shows ELB Security Group Creation under VPC section

ELB Security Group Creation

 

Setting Option
Name XKCDAppElasticLoadBalancerSecurityGroup
Description XKCDApps Elastic Load Balancer Security Group.
VPC Select your VPC, or use the default one.
Inbound Rules Type: HTTP, Source: Anywhere
Inbound Rules Type: HTTPS Source: Anywhere
Inbound Rules Type: CustomTCP, Port Range: 8000, Source: Anywhere
Outbound Rules Type: All Trafic, Destination: Anywhere

 

5.2 ELB Creation

Go to Load Balancers under EC2 and click on Create Load Balancer button and select Application Load Balancer.

5.2.1 - Step 1: Configure Load Balancer Image shows basic configurations for Load Balancer in ELB Creation

ELB Creation: Configuring load balancer

 

For Availability Zones, you should remember your AZ choices, as you will need to use same configuration for Elastic Container Service creation.

Image shows  configuration of  availability zones

ELB Creation: Configuring availability zones

 

Setting Option
Load Balancer Type Application Load Balancer
Name XKCDAppELB
Scheme internet-facing
IP address type ipv4
Listeners HTTP: 80
Listeners HTTP: 8000
Availability Zones 2a, 2b, 2c

 

5.2.2 - Step 2: Security Settings

Image shows step 2 security settings for ELB  configuration

ELB Creation: Target Group creation

We are not going to use HTTPS for this demo, feel free to skip this step.

5.2.3 - Step 3: Security Groups

Image shows configuration of Security Groups in ELB Creation

ELB Creation: Security Group selection

5.2.4 - Step 4: Routing: Target Group Creation

 image shows Target Group creation in ELB Creation

ELB Creation: Target Group creation

 

Setting Option
Target Group New target group
Name XKCDAppClusterServiceTargetGroup
Target Type IP
Protocol HTTP
Port 8000
Protocol version HTTP1
Health Checks: Protocol HTTP
Health Checks: Path /

 

5.2.5 - Step 5: Registering Targets to Target Group

Feel free to skip this step, ECS will going to manage target groups.

5.2.6 - Step 6: Review

Click on create button. And when you go back to Load Balancers console, you should see something like this.

Name DNS name state
XKCDAppELB XKCDAppELB-123456789.eu-west-2.elb.amazonaws.com provisioning

We will be using the DNS name to connect to our ECS instances, take a note of it.

5.2.7 - Step 7: Forward traffic from port 80 to port 8000

Go to Listeners tab on XKCDAppELB's detail view under Load balancers. On listener HTTP: 80 click on view/edit rules.

image shows ELB Port Forwarding in Target Group creation

ELB Port Forwarding: Target Group creation

Add a rule to forward HTTP:80 traffic to HTTP:8000.

Setting Option
Path *
Redirect to HTTP 8000
HTTP Code 301 - Permanently Moved

image shows Adding a rule to load balancer for port forwarding

Port Forwarding: Adding a rule Group creation

6. Elastic Container Service

6.1 Creating an ECS Task Execution Role: XKCDAppECSTaskExecutionRole

Go to Role under IAM and click on create Role button. Attach policies below:

  1. AmazonECSTaskExecutionRolePolicy (aws managed)
  2. SystemManagerParameterStoreFullAccess (custom)

Image shows ECS Task Role Creation

ECS Task Role Creation

 

6.2 Creating ECS security group: XKCDAppECSSecurityGroup

 image shows Creating ECS security group as named  XKCDAppECSSecurityGroup

Creating ECS security group: XKCDAppECSSecurityGroup

 

Setting Option
Name XKCDAppECSSecurityGroup
Description XKCD Apps security group, allows container ports
VPC Select your VPC, or use the default one.
Inbound Rules Type: CustomTCP, Port Range: 80, Source: Anywhere
Inbound Rules Type: CustomTCP, Port Range: 8000, Source: Anywhere
Outbound Rules Type: All Trafic, Destination: Anywhere

 

6.3 Creating Task Definition: XKCDAppTaskDefinition

Go to Task Definitions under Elastic Container Service and create task definition.

 image shows task configuration and container definitions  image shows task configuration and container definitions

Configure task and container definitions

 

Setting Option
Launch Type Fargate
Name XKCDAppTaskDefinition
Task Role XKCDAppECSTaskExecutionRole
Network mode awsvpc
Task Execution Role ecsTaskExecutionRole
Task Memory 2 GiB
Task CPU 1vCPU

 

6.3.1 Adding a container to XKCDAppTaskDefinition

Click on Add container button under the section Container Definitions

 image shows Adding a container to XKCDAppTaskDefinition

Remember to append :latest tag to your Elastic Container Registry URI.

Setting Option
Container name XKCDAppContainer
Image 12345678912.dkr.ecr.eu-west-2.amazonaws.com/xkcdapp:latest
Port Mappings 8000 TCP
Port Mappings 80 TCP

 

6.4 Creating Cluster Service

Click on the default cluster on Clusters page under Elastic Container Service.

image shows how to Create Cluster Service as AWS ECS default cluster

AWS ECS default cluster

Click on Create button under Services.

 

6.4.1 - Step 1: Configure Service image shows how to configure an ECS Cluster Service

 

Setting Option
Launch Type Fargate
Task Definition XKCDAppTaskDefinition
Task Revision 1(latest)
Platform Version Latest
Cluster default
Service name XKCDAppClusterService
Service Type Replica
Number of tasks 1
Min healty percent 100
Max percent 200

 

6.4.2 - Step 2: Configure Network

VPC & Security Group

 image shows how to Cluster Service’s network configuration

 

Setting Option
Cluster VPC default
Subnets 2a, 2b, 2c
Security Group Select existing: XKCDAppECSSecurityGroup
Auto-assign public IP ENABLED

 

Load Balancing

 image shows load balancing options and application load balancer is selected.

 

Setting Option
Load Balancer Type Application Load Balancer
Load Balancer Name XKCDAppELB

 

Container to load balance

 image shows load balancing options and application load balancer is selected.

 

Setting Option
Production Listener Port 80:HTTP
Production Listener Protocol HTTP
Target group name Select existing: XKCDAppClusterServiceTargetGroup
Target group protocol HTTP
Target type IP
Path Pattern /
Evaluation Order default
Health check path /

 

6.4.3 - Step 3: Set Auto Scaling

We will configure auto scaling later. Skip this step for now.

6.4.4 - Step 4: Review

Make sure your changes are correct and click on Create Service button.

Go to Tasks tab under Service: XKCDAppClusterService, and wait for your task's status to be RUNNING.

Now you can go to your Elastic Load Balancer's DNS name which is something like this: http://xkcdappelb-12346578.eu-west-2.elb.amazonaws.com:8000/

If you haven't done the ELB port forwarding remember to append the port :8000 to DNS name.

6.5 Load Testing our App with Hey

Hey is an open-sourced load testing tool. We will be using it to test how well a single container of XKCD App does under load. And with the information we get out of load-testing, we can decide on a good Auto Scaling Policy.

Let's run hey with 100 requests, 1 concurrent request at a time.

❯ hey -n 100 -c 1 http://xkcdappelb-123456789.eu-west-2.elb.amazonaws.com:8000/

Summary:
  Total:    64.8392 secs
  Slowest:  1.6920 secs
  Fastest:  0.1304 secs
  Average:  0.6484 secs
  Requests/sec: 1.5423
  
  Total data:   109851 bytes
  Size/request: 1098 bytes

Response time histogram:
  0.130 [1] |■
  0.287 [6] |■■■■■■
  0.443 [22]    |■■■■■■■■■■■■■■■■■■■■
  0.599 [7] |■■■■■■■
  0.755 [43]    |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.911 [1] |■
  1.067 [16]    |■■■■■■■■■■■■■■■
  1.224 [2] |■■
  1.380 [0] |
  1.536 [1] |■
  1.692 [1] |■


Latency distribution:
  10% in 0.3377 secs
  25% in 0.3638 secs
  50% in 0.6604 secs
  75% in 0.7351 secs
  90% in 1.0325 secs
  95% in 1.0596 secs
  99% in 1.6920 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0065 secs, 0.1304 secs, 1.6920 secs
  DNS-lookup:   0.0058 secs, 0.0000 secs, 0.5765 secs
  req write:    0.0000 secs, 0.0000 secs, 0.0001 secs
  resp wait:    0.6418 secs, 0.1302 secs, 1.5321 secs
  resp read:    0.0001 secs, 0.0000 secs, 0.0003 secs

Status code distribution:
  [200] 100 responses

In almost a minute, our application responded to 100 requests and it responded in average of 0.64 second. You can try to experiment with hey, change the request count, update your Task Definition's RAM or vCPU etc.

That's the ideal situation for XKCD App, so we will configure Auto Scaling condition to be 100 requests per minute per instance.

6.6 Creating Auto Scaling for XKCDAppClusterService

Go to XKCDAppClusterService under default cluster and click update.

 image shows Configuration of AWS ECS Auto Scaling

Configuring AWS ECS Auto Scaling

 

Set up a reasonable Auto Scaling Policy. Configuring AWS ECS Auto Scaling Policy

Configuring AWS ECS Auto Scaling Policy

 

6.6.1 Testing the Auto Scaling Policy

Normally, XKCDAppClusterService's desired count of instances is 1.

Configuring AWS ECS Auto Scaling: POC before

But when I load-test it again with hey,

❯ hey -n 400 -c 10 http://xkcdappelb-123456798.eu-west-2.elb.amazonaws.com:8000/

I could see that my instance count is increased after cool-down time.

 image shows a proof of concept for ECS Auto Scaling policy

7. Updating Security Groups

Our XKCD App runs on the security group configuration of below diagram.

diagram shows the entire the security group configuration that XKCD App runs on

If we follow the access through the security groups, we can come up with a inbound/outbound access table:

inbound outbound
Public Internet XKCDAppElasticLoadBalancerSecurityGroup
XKCDAppElasticLoadBalancerSecurityGroup XKCDAppECSSecurityGroup
XKCDAppECSSecurityGroup XKCDAppElastiCacheSecurityGroup
XKCDAppECSSecurityGroup XKCDAppRDSSecurityGroup

Let's update our security groups. Go to Security Groups under VPC.

 

7.1 Updating XKCDAppElasticLoadBalancerSecurityGroup

Select XKCDAppElasticLoadBalancerSecurityGroup and edit the rules.

Rule Type Type Destination Type Destination
Inbound HTTP:80 Anywhere
Inbound Custom TCP: 8000 Custom Anywhere
Outbound All Traffic Custom XKCDAppECSSecurityGroup

 

7.2 Updating XKCDAppECSSecurityGroup

Select XKCDAppECSSecurityGroup and edit the rules.

Rule Type Type Destination Type Destination
Inbound HTTP:80 Custom XKCDAppElasticLoadBalancerSecurityGroup
Inbound Custom TCP: 8000 Custom XKCDAppElasticLoadBalancerSecurityGroup
Outbound All Traffic Anywhere
Outbound Custom TCP: 6379 Custom XKCDAppElastiCacheSecurityGroup
Outbound Custom TCP: 5432 Custom XKCDAppRDSSecurityGroup

 

7.3 Updating XKCDAppElastiCacheSecurityGroup

Select XKCDAppElastiCacheSecurityGroup and edit the rules.

Rule Type Type Destination Type Destination
Inbound TCP: 6379 Custom XKCDAppECSSecurityGroup

 

7.4 Updating XKCDAppRDSSecurityGroup

Select XKCDAppRDSSecurityGroup and edit the rules.

Rule Type Type Destination Type Destination
Inbound TCP: 5432 Custom XKCDAppECSSecurityGroup

Conclusion

If you’ve followed this blog post to the end, you should have a secure AWS environment where a Django app is served on Elastic Container Service at scale. We created multiple services for our application’s needs, and configured their network settings to accept traffic from where they’re supposed to. And also, our application secrets are located securely in the AWS Parameter Store.

If you would like to tighten the security of your AWS environment, please consider configuring your VPC securely. You can read more about secure VPC design on our previous blog post Secure AWS VPC Design and Configuration Guide.

If you liked this post, share it now!

Our Recent Posts

How to Secure Your Docker Containers: Tips and Challenges

Discover Docker technology, learn about Docker security best practices and Docker vulnerability...

Read More

Ultimate Guide to Securely Deploy Django at Scale on AWS ECS [Part 3]

Learn how to securely deploy a dockerized Django application to AWS Elastic Container Service w...

Read More

Ultimate Guide to Securely Deploy Django at Scale on AWS ECS [Part 2]

Learn how to securely deploy a dockerized Django application to AWS Elastic Container Service w...

Read More