Building a Scalable Web App with AWS Elastic Beanstalk, DynamoDB, CloudFront, and Edge Location - with AWS Dashboard and EB CLI
Tags: ebcli, aws, elasticbeanstalk, cloud
Published: 2024-07-02 18:22:44

![](https://miro.medium.com/v2/format:webp/1*mxCDCTUxKMbrrEJtvDT4xA.png)




In this real-world project, I was tasked with implementing an application capable of supporting a high volume of simultaneous users. This application was utilized during a large conference attended by over 10,000 people, both in-person and online, from around the globe. The event featured live broadcasts and the drawing of 10 vouchers for 3 Cloud certifications. At the peak moment, more than 10,000 audience members registered their emails to participate in the raffle.

We used AWS, Elastic Beanstalk services to deploy the web application, DynamoDB to store emails, and CloudFront to cache static and dynamic files in an Edge Location close to the user.

## Solution Architecture

![](https://miro.medium.com/v2/format:webp/1*mZU0mWyGPiZoGrobEqdphA.png)

**Part 1: Create a table in DynamoDB to store users’ email addresses and deploy the application using Elastic Beanstalk**

**Part 2: Create a CloudFront distribution**

**Part 3: Perform Load testing**

## Part 1: Create a table in DynamoDB to store users’ email addresses and deploy the application using Elastic Beanstalk

Create a table in DynamoDB to store users’ email addresses and deploy the application using Elastic Beanstalk, which will provision infrastructures such as EC2, Elastic Load Balancer, and Auto Scaling group.

 1. **Create a table in DynamoDB to store users’ email addresses**

Amazon DynamoDB is a fully managed, high-performance, and highly scalable NoSQL database service designed to handle large-scale data loads and ensure low-latency responses.

Search for DynamoDB in the AWS console and create a table “users”. Leave anything else as default.

A partition key is a unique attribute in a DynamoDB table that determines the partition in which the data is stored. Each item in the table must have a unique value for the partition key.

Table name: users

Partition key: email, type String

![](https://miro.medium.com/v2/format:webp/1*m18oCx8wgqXRVgFDbx7zOQ.png)

**2. Create an Elastic Beanstalk Application**

Amazon Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.

Many people will try accessing our application from a mobile or desktop to register. At this stage, the application needs to be robust and scalable to handle high traffic from many users. Elastic Beanstalk allows us to deploy and manage the web application in AWS Cloud without worrying about the infrastructure. It simplifies the process by provisioning and managing essential AWS resources like EC2 instances, Elastic Load Balancers, and Auto Scaling groups, ensuring the application remains responsive and available under varying loads. We will upload the application files, and Elastic Beanstalk will automatically manage capacity provisioning, load balancing, and scaling.

Elastic Beanstalk will use the provided application files to deploy the application. It is important to organize the application folders in a way that Elastic Beanstalk can understand. Check the [Elastic Beanstalk documentation](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/tutorials.html) before uploading the application files. Each application requires its own folder structure. This project’s folders and files were designed specifically for the Python application.

![](https://cdn-images-1.medium.com/max/2000/0*ueDTEsvN4amAyDyv.png)

application.py

    from flask import Flask, render_template, flash, redirect, url_for, session, request, logging
    from wtforms import Form, StringField, TextAreaField, PasswordField, validators
    from wtforms.validators import InputRequired, Email
    import boto3
    import os
    from urllib.parse import quote as url_quote

    application = Flask(__name__)
    
    #dynamodb = boto3.resource('dynamodb', endpoint_url="http://localhost:8000")
    region = os.environ['AWS_REGION']
    dynamodb = boto3.resource('dynamodb',region_name=region)
    
    def put_user(email):
        table = dynamodb.Table('users')
        response = table.put_item(
           Item={
                'email': email
            }
        )
        return response
    
    # Index
    @application.route('/', methods=['GET', 'POST'])
    def index():
        form = RegisterForm(request.form)
        if request.method == 'POST' and form.validate():
            user_resp = put_user(form.email.data)
            return render_template('obrigado.html')
        
        return render_template('index.html', form=form)
    
    # Register Form Class
    class RegisterForm(Form):
        email = StringField('Email', [InputRequired("Please enter your email.")])
    
    if __name__ == '__main__':
        application.secret_key='secret123'
        application.run(debug=True)

requirements.txt

    boto3==1.21.8
    botocore==1.24.8
    Flask==2.0.3
    passlib==1.7.2
    WTForms==2.3.3
    jsons==1.6.1
    itsdangerous==2.1.0
    Werkzeug==2.0.3

Proper organization of the application files helps Elastic Beanstalk deploy the application automatically. Structure your project, zip, and store the zip file in a S3 bucket or locally. Elastic Beanstalk will use it to deploy the application.

**3. Configure environment**

Search for Elastic Beanstalk in the AWS console and “**Create Application”.**

Application name: tcb-conference

Platform (runtime environment): Python 3.8

Application code: Upload the application file code

Presets: High availability

![](https://cdn-images-1.medium.com/max/3560/0*96GsS-oAhPV3ObZQ.png)

It launches an environment named tcb-conference-env with these [AWS resources:](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/GettingStarted.CreateApp.html)

* An Amazon Elastic Compute Cloud (Amazon EC2): An Amazon EC2 virtual machine configured to run web apps on the platform you choose.

* An Amazon EC2 security group: An Amazon EC2 security group configured to allow incoming traffic on port 80. This resource lets HTTP traffic from the load balancer to the EC2 instance running your web app.

* An Amazon Simple Storage Service (Amazon S3) bucket: A storage location for your source code, logs, and other artifacts that are created when you use Elastic Beanstalk.

* Amazon CloudWatch alarms: Two CloudWatch alarms that monitor the load on the instances in your environment and are triggered if the load is too high or too low. When an alarm is triggered, your Auto Scaling group scales up or down in response.

* An AWS CloudFormation stack: Elastic Beanstalk uses AWS CloudFormation to launch the resources in your environment and propagate configuration changes. The resources are defined in a template that you can view in the [AWS CloudFormation console.](https://console.aws.amazon.com/cloudformation)

* A domain name (autogenerated in our case): A domain name that routes to your web app in the form [subdomain.region.elasticbeanstalk.com](http://subdomain.region.elasticbeanstalk.com).

![](https://cdn-images-1.medium.com/max/2420/0*ZpRAsH9Mt0A0o1OV.png)

We do not need to specify the S3 bucket URL at this point. Once we move to the next step (from environment configuration to service access configuration) an S3 bucket will be automatically created without waiting to complete the EBS application creation process. We can use this bucket to store our application code or create a different one. I will use this one.

![](https://cdn-images-1.medium.com/max/4068/0*UZCWISQcmZ8_INQ5.png)

After designing the folder structure for the Python application based on AWS Elastic Beanstalk documentation, the application files will be uploaded to S3 bucked. That location is used to run the application. Go to S3 bucked and upload the application files.

![](https://cdn-images-1.medium.com/max/2360/0*Tnf2XE-rlmow_1aH.png)

![](https://cdn-images-1.medium.com/max/4760/0*-kIsORSNbmqGpmt1.png)

Update your Public S3 URL with the bucket URL.

![](https://cdn-images-1.medium.com/max/2432/0*jIjgVnWgSvxSkksy.png)

At this point, all public access to this bucket is allowed as default. I will keep it as it is but update it for later projects.

**4. Configure service access**

We need to set up the necessary permissions and roles that allow Elastic Beanstalk to interact with other AWS services securely.

 1. **Service Role**: Grants permissions to the Elastic Beanstalk service itself, allowing it to manage AWS resources on your behalf. This includes creating and managing EC2 instances, load balancers, and other resources necessary for running your application.

 2. **EC2 Instance Profile:** Grants permissions to the EC2 instances running our application. It allows the instances to interact with other AWS services (e.g., S3, DynamoDB) on your behalf.

![](https://cdn-images-1.medium.com/max/3764/0*2BsRccBwAaC1WhQX.png)

When you click View permission details you will see recommended permission by AWS. We will add them to our IAM roles as well.

**Service role permission recommendations:**

 1. **AWSElasticBeanstalkEnhancedHealth** (this comes as default)

 2. **AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy** (we will attach it)**:** This policy is for the AWS Elastic Beanstalk service role used to perform managed updates of Elastic Beanstalk environments. The policy grants broad permissions to create and manage resources across several AWS services including AutoScaling, EC2, ECS, Elastic Load Balancing, and CloudFormation.

**EC2 instance profile recommendations:**

 1. **AWSElasticBeanstalkWebTier:** Provide the instances in your web server environment access to upload log files to Amazon S3.

 2. **AWSElasticBeanstalkWorkerTier:** Provide the instances in your worker environment access to upload log files to Amazon S3, to use Amazon SQS to monitor your application’s job queue, to use Amazon DynamoDB to perform leader election, and to Amazon CloudWatch to publish metrics for health monitoring.

 3. **AWSElasticBeanstalkMulticontainerDocker:** Provide the instances in your multicontainer Docker environment access to use the Amazon EC2 Container Service to manage container deployment tasks.

First, we need to create an IAM role and attach it to the Elastic Beanstalk application. You can select *Create and use a new service role* if you do not have an existing one, or you want AWS to create one for you. This will create an IAM role with necessary permissions but you may need to add additional permissions based on your application needs. I will create a new one for this project following the steps below:

 1. **Create a Service Role**:

Go to IAM -> Roles -> Create role -> AWS service

![](https://cdn-images-1.medium.com/max/3868/0*D49yFluVQeXUkALl.png)

When we specify the Use case as Elastic Beanstalk it comes with some [default policies.](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts-roles-service.html)

![](https://cdn-images-1.medium.com/max/4844/0*KA82knGXtaRW6eEJ.png)

Named :elastic-beanstalk-service-role

**AWSElasticBeanstalkEnhancedHealth:** AWS Elastic Beanstalk Service policy for Health Monitoring system.

**AWSElasticBeanstalkService:** AWS Elastic Beanstalk Service role policy grants permissions to create & manage resources (i.e.: AutoScaling, EC2, S3, CloudFormation, ELB, etc.) on your behalf. This policy comes with the following permissions by default:

* **AllowCloudformationOperationsOnElasticBeanstalkStacks**: Allows full CloudFormation operations.

* **AllowDeleteCloudwatchLogGroups**: Allows Elastic Beanstalk to clean up log groups when environments are deleted.

* **AllowECSTagResource**: Allows tagging of ECS resources

* **AllowS3OperationsOnElasticBeanstalkBuckets**: Allows full S3 operations on Elastic Beanstalk-specific buckets. Grants permissions to manage Elastic Beanstalk application versions, environment configurations, and logs stored in S3 buckets.

* **AllowLaunchTemplateRunInstances**: Enables Elastic Beanstalk to launch EC2 instances using predefined launch templates.

* **AllowOperations**: Allows Elastic Beanstalk to fully manage instances, security groups, load balancers, scaling policies, and other resources necessary for the application environment. Includes permissions for Auto Scaling, EC2, ECS, Elastic Load Balancing, IAM, CloudWatch, RDS, S3, SNS, SQS, and CodeBuild.

![](https://cdn-images-1.medium.com/max/3212/0*CyS6jIPiIeHRElS0.png)

Most of the necessary policies are attached by default. Create a role with given permissions first. If we need any additional permission we need to attach it to this role.

![](https://cdn-images-1.medium.com/max/4144/0*hTH4zxaVrGzx56pb.png)

We will attach the recommended policy we mentioned earlier: **AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy**

![](https://cdn-images-1.medium.com/max/4024/0*RTZUH7S8yg322eOb.png)

**AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy**: Includes permissions needed specifically for updating instances and other resources.

**AWSElasticBeanstalkService**: Includes a wider range of permissions necessary for creating, updating, and deleting various AWS resources managed by Elastic Beanstalk. This policy is on a deprecation path. It comes as a default for now.

**2. Create an EC2 Instance Profile**

We will follow similar steps to create an EC2 Instance Profile.

![](https://cdn-images-1.medium.com/max/4860/0*UB8xwU2ypDipUesW.png)

We need to attach specific policies to give additional permission to the EC2 instance that our Python application will run inside it. In our case, our application needs to write data and read data from the DynamoDB table. We need a specific policy for that which is *AmazonDynamoDBFullAccess.*

![](https://cdn-images-1.medium.com/max/4748/0*x9WDQKxXxy5-YiR8.png)

Named :elastic-beanstalk-ec2-service-role

After we added AWS recommended policies, the final role comes with the following policies:

![](https://cdn-images-1.medium.com/max/3948/0*NnBfal262_rPWtq3.png)

**3. Create an SSH key:**

To access the EC2 instance via SSH connection we will create an SSH key.

EC2 -> Key pairs -> Create key pair

![](https://cdn-images-1.medium.com/max/2784/0*NZoKx_YJUwSDH-Ek.png)

Download and store the key.

We are all set for service access configuration.

![](https://cdn-images-1.medium.com/max/3672/0*7SkNKbEIWYiHGP62.png)

You can *Skip to review* and edit configuration there or you can go step by step until the end.

**5. Set up networking, database, and tags-[optional](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.vpc.html)**

If you don’t configure a VPC, Elastic Beanstalk uses the default VPC. I will use a custom VPC I had before. You can use the default one. The configuration will be the same.

![](https://cdn-images-1.medium.com/max/4264/0*FaLnOX3T1NmaICm2.png)

We will choose subnets in each AZ for the EC2 instances that run our application. To avoid exposing our application instances to the Internet, we can run them inside private subnets and load balancers in public subnets such that our application will be open the public access through NAT. If we choose private subnets for our EC2 instances, the VPC must have a NAT gateway in a public subnet that the EC2 instances can use to access the Internet. I will not create a NAT gateway and I will run both in public subnets for simplicity. To run the load balancer and instances in the same public subnets, we will assign public IP addresses to the instances.

![](https://cdn-images-1.medium.com/max/2988/0*NmiEGuP9aLyGC6ni.png)

I only picked public subnets and activated public IP addresses for EC2 instances. I am not going to use RDS, I will move to the next configuration.

**6. Configure instance traffic and scaling *— optional***

We will set the Root volume type: General Purpose SSD — 8 GB

![](https://cdn-images-1.medium.com/max/3476/0*ej7MY95wQeuteBTi.png)

***Capacity:***Instances Min: 2 Instances Max: 4 Instance type: t2-micro

![](https://cdn-images-1.medium.com/max/2416/0*epIeRMMSJkTZppzj.png)

The Elastic Beanstalk will automatically create a Load Balancer for our application, with a minimum of 2 EC2 instances running when we first launch our application, and a maximum of 4 if triggered.

Configure the trigger that lets the auto-scaling group know when to scale up and add up more instances. if the load goes beyond 50% of CPU utilization, it is going to add more instances up to 4 to keep up with the workload.

***Scaling triggers:***

![](https://cdn-images-1.medium.com/max/2144/0*JlPzlEqa2pmrtaAv.png)

***Load balancer network settings:*** We will use the same setting as we used for EC2 instances.

![](https://cdn-images-1.medium.com/max/2152/0*xqeqKUd7cvYbEcqv.png)

***Listeners:*** By default, the load balancer is configured with a standard web server on port 80. I will use default settings.

![](https://cdn-images-1.medium.com/max/2120/0*UNOgUFfdyomVygEh.png)

If you wish you can configure Elastic Load Balancer to capture logs with detailed information about requests sent to your Load Balancer. Those logs will be stored in Amazon S3. I will not enable it for this project.

![](https://cdn-images-1.medium.com/max/2208/0*WM5NNU8i6Riq-4UL.png)

**7. Configure updates, monitoring, and logging *— optional***

I will not touch settings here, if you want you can configure them based on your needs. It uses NGINX by default.

![](https://cdn-images-1.medium.com/max/3284/0*T_sfDDK_mWoadTz3.png)

![](https://cdn-images-1.medium.com/max/3420/0*zkHw224dQCIlDHte.png)

I will only set the AWS_REGION environment variable here. It will be passed to my application.

![](https://cdn-images-1.medium.com/max/2156/0*Z6ZCv3V72Zf7MSKV.png)

Submit to create the environment for the application run. It takes a few minutes.

![](https://cdn-images-1.medium.com/max/4216/0*aVGmlF_bHDJsMkNH.png)

***S3 Bucket:***

![](https://cdn-images-1.medium.com/max/4180/0*3UNJKn5OF338Ubtd.png)

***EC2 instances:***

![](https://cdn-images-1.medium.com/max/4492/0*lLsjUMX8urMeuMEr.png)

***Security Groups:***

![](https://cdn-images-1.medium.com/max/4392/0*93NeAFTWzznpvslR.png)

Inbound-outbound rules of security groups:

![](https://cdn-images-1.medium.com/max/4228/0*oBduRmnK9sniLG4F.png)

![](https://cdn-images-1.medium.com/max/4192/0*g7D-XmRzWwuXzg76.png)

![](https://cdn-images-1.medium.com/max/4212/0*zuLxFJU7MVlZgYNc.png)

***Load Balancer:***

![](https://cdn-images-1.medium.com/max/4260/0*v0OdhrXZD-0hGfmH.png)

The environment health turned to RED, I will look at the logs and figure it out before trying to run my application.

![](https://cdn-images-1.medium.com/max/4976/0*bNetjzXXCUADK9bQ.png)

It did not work in my case. I ran this application without any problem with the same settings before. It should work. I do not know if AWS has updated any settings on its services since my last run. I got the following error for this time:

ERROR: ModuleNotFoundError: No module named 'application'

I applied the solutions below to solve it but I was not able to solve this error after too much debugging.

* AWS calls the Flask instance as an *application* but Gunicorn calls it as an *app.* I updated a line, application = app = Flask(__name__), in my *application.py* file and then set WSGIPath to application:application.

I will use EB CLI after this point with the exact same settings. If you are also not able to run or debug by yourself you can move with me to use EB CLI.

Do not forget to destroy all the resources you created with Elastic Bean Stalk; *tcb-conference-env* and *tcb-conference* application. Keep the DynamoDB table.

## Building a Scalable Web App with AWS Elastic Beanstalk, DynamoDB, and CloudFront — with EB CLI

## Part 1: Deploy the application using Elastic Beanstalk — with EB CLI

 1. **Install EB CLI**

EB CLI is AWS Elastic Beanstalk Command Line Interface. First, we will install EB CLI. You can use this [aws-elastic-beanstalk-cli-setup](https://github.com/aws/aws-elastic-beanstalk-cli-setup?tab=readme-ov-file#macoslinux) to install based on your operating system. I will follow the instructions for MacOS:

    pip install awsebcli
    # Verify the EB CLI Installation
    eb --version

**2. Configure the EB CLI**

Initialize an EB CLI project and select your region.

    # Initialize 
    eb init
    
    #or
    eb init -p python-3.8 tcb-conference --region us-east-1

![](https://cdn-images-1.medium.com/max/3860/0*zrvpz6hHlkO01h94.png)

**3. Setup IAM Credentials**

We must provide our credentials first. We must provide a secret key and access key to authenticate (who we are) and authorize (what permission we do have) to allow EB CLI to access and manage AWS resources for us. Let’s go to the IAM console to create a secret and access key. The secret access key is available for download only when you create it, make sure you download it after you create it.

Go to IAM console -> Users -> Create User

![](https://cdn-images-1.medium.com/max/4796/0*BXiCWRl2zE8b6Ink.png)

I will give AdministratorAccess access, and I can update later if I wish.

![](https://cdn-images-1.medium.com/max/4860/0*r7BK4I90wZkUps54.png)

Go and create access key.

Use case: Command Line Interface (CLI)

![](https://cdn-images-1.medium.com/max/4048/0*GFKBB82fJuDcJmS_.png)

When you run EB CLI it will ask for these credentials. You can also configure the AWS CLI using environment variables

export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID

export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY

export AWS_DEFAULT_REGION=us-east-1

We are ready to configure the EBS environment, similar to what we did on the AWS console before:

![](https://cdn-images-1.medium.com/max/3748/0*kQ1v61MO_bg0mIv7.png)

**4. Create an Elastic Beanstalk Environment**

We will use the YAML file for configuration. The YAML file should be under *.ebextentions*. EBS will automatically detect and run this config file when it is provided. Otherwise, it will use default EBS settings to create an EBS environment.

    mkdir .ebextensions 
    touch .ebextensions/environment_configuration.config

![](https://cdn-images-1.medium.com/max/2000/0*d0lxPV_wvcHKU2wn.png)

![](https://cdn-images-1.medium.com/max/2124/0*DcGAxQ9wS9O-x73N.png)

Our application files will be zipped and uploaded to the S3 bucket while creating the environment.

We will use the same configuration in our YAML file. This is actually easier and faster compared to using AWS Dashboard.

YAML config file:

    option_settings:
      aws:elasticbeanstalk:environment:
        ServiceRole: "aws-elasticbeanstalk-service-role" # Set service role
      aws:autoscaling:launchconfiguration:
        InstanceType: t2.micro # Specify the instance type (adjust as needed)
        EC2KeyName: ebs-ssh-key # Set EC2 key pair
        IamInstanceProfile: aws-elasticbeanstalk-ec2-role # Set IAM instance profile
        RootVolumeType: gp2
        RootVolumeSize: "10"
        DisableIMDSv1: true # Deactivate IMDSv1
      aws:autoscaling:asg:
        MaxSize: 4 # Maximum number of instances
        MinSize: 2 # Minimum number of instances
      aws:ec2:vpc:
        VPCId: "vpc-03f8678fb9c5d5ea1" # Set the VPC ID
        ELBScheme: public
        Subnets:
          - "subnet-0449c3e40202e7665"
          - "subnet-01e26ba1a707f5b13"
          - "subnet-06a672c7f4aea1795"
          - "subnet-0461ac2c4cea08257"
        ELBSubnets:
          - "subnet-0449c3e40202e7665"
          - "subnet-01e26ba1a707f5b13"
          - "subnet-06a672c7f4aea1795"
          - "subnet-0461ac2c4cea08257"
        AssociatePublicIpAddress: true # Enable public IP addresses for instances
      aws:elasticbeanstalk:healthreporting:system:
        SystemType: "basic" # Enable enhanced health reporting
      aws:autoscaling:trigger:
        MeasureName: "CPUUtilization" # Use CPUUtilization as trigger measurement
        UpperThreshold: "50" # Upper threshold for CPU utilization
        LowerThreshold: "40" # Lower threshold for CPU utilization
        Unit: "Percent"
        Period: "1"
        UpperBreachScaleIncrement: "1" # Increase instance count by 1 on upper breach
        LowerBreachScaleIncrement: "-1" # Decrease instance count by 1 on lower breach
      aws:elasticbeanstalk:container:python:
        WSGIPath: "application:application" # Set WSGIPath to application:application
      aws:elasticbeanstalk:application:environment:
        AWS_REGION: "us-east-1" # Set AWS_REGION environment property

You can use [EBS documentation](https://docs.aws.amazon.com/pdfs/elasticbeanstalk/latest/dg/awseb-dg.pdf#command-options-general) here while preparing your YAML file.

Ready to create an EBS environment:

    eb create tcb-conference-env --region us-east-1

![](https://cdn-images-1.medium.com/max/5120/0*94y87p7tVydQJIje.png)

We are now able to create our EBS environment without any problems at this time!

Health: OK

![](https://cdn-images-1.medium.com/max/4064/0*E7xiJD3XBFv8zTVX.png)

Click on the Domain name to open the application:

![](https://cdn-images-1.medium.com/max/3152/0*7vFetVgxw8n0jSBx.png)

Our application files were zipped and uploaded to the S3 bucket. Remember we created an EBS application named *tcb-conference* at the beginning of the EB CLI initialization. Our files are zipped and placed in a directory named *tcb-conference.*

*S3 bucket:*

![](https://cdn-images-1.medium.com/max/4772/0*Y0D9LQKIRHt-_uHA.png)

*EC2 instances (Minimum 2):*

![](https://cdn-images-1.medium.com/max/4984/0*wDTna15NaXLAhvZg.png)

*Load Balancer:*

![](https://cdn-images-1.medium.com/max/4200/0*q39EjotpNEbqMeDZ.png)

*Auto Scaling Group:*

![](https://cdn-images-1.medium.com/max/4152/0*hMr5HG3M2LSzmpBt.png)

*CloudFormation:*

![](https://cdn-images-1.medium.com/max/4208/0*kKDl8vXIpJWrsbjF.png)

**5. Validate the Application**

The participants will need to enter their email address on the web page and the application will insert the email address into the DynamoDB.

Try to register:

![](https://cdn-images-1.medium.com/max/3124/0*HGcSlJDKqwLiprhw.png)

![](https://cdn-images-1.medium.com/max/3980/0*hQgrgC6zXI3QZUcH.png)

Upps! We are not able to register. Our frontend is working but we are not allowed to register. Our email will not be written to DynamoDB. Let’s go and check our EC2 instance role.

![](https://cdn-images-1.medium.com/max/4076/0*iOiRVgrBVg25fa8b.png)

We do not have permission to write data to DynamoDB. Permit your EC2 instance to write data on the DynamoDB table inside the IAM role. Add the permission **AmazonDynamoDBFullAccess** on the EC2 associate role in IAM.

![](https://cdn-images-1.medium.com/max/4688/0*RC57tC5R5LOaLZzY.png)

Try again:

![](https://cdn-images-1.medium.com/max/3472/0*jao8Tew-7DSApR1U.png)

Check the *users’* DynamoDB table:

![](https://cdn-images-1.medium.com/max/4116/0*-G-LtBLNTxzbe6sp.png)

Awesome!

## Part 2: Create a CloudFront Distribution

The CloudFront is a Content Delivery Network. All the static and dynamic files (CSS, HTML, etc) coming from the application will be cached on the edge location closer to the user so that it can improve the application’s performance and provide the lowest latency. When a user requests content, the request is routed to the edge location.

Go to Console and search for CloudFront -> Create a CloudFront distribution

Our application origin is our Elastic Load Balancer.

![](https://cdn-images-1.medium.com/max/2500/0*4gyrTMqPu9yMHJAG.png)

![](https://cdn-images-1.medium.com/max/2420/0*bFX-3MEFat36Rd5s.png)

* Cache policy: CachingOptimized

* Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE. We want to allow the POST method to insert the data inside DynamoDB.

![](https://cdn-images-1.medium.com/max/2416/0*SBOmJYfNEPNRUrhJ.png)

![](https://cdn-images-1.medium.com/max/2424/0*J3Ka-vowkuYolYNG.png)

![](https://cdn-images-1.medium.com/max/2420/0*2cn2fPRLc66idoF2.png)

* Once CloudFront distribution is created, a domain name to access our application is already associated with it. This will give the Route 53 DNS entry that we use to access the application throughout CloudFront.

* We could have a Custom SSL certificate — (optional), branded and customized domain name for our purpose associated with our CloudFront distribution and put the SSL certificate associated with that as well. We are going to use the default one created for us.

![](https://cdn-images-1.medium.com/max/4800/0*_oCEduCKnmyC0nGX.png)

Copy the CloudFront domain name when it is ready. Let’s confirm if we can access the application using the CloudFront.

Here it is:

![](https://cdn-images-1.medium.com/max/3504/0*ASJgTA7a-UIv7j8O.png)

## Part 3: Perform Load testing

We will basically simulate here what will happen if many users are accessing to EC2 instance at the same time and CPU utilization goes up.

We will induce load on the CPU. Copy the IP address from one of the EC2 instances. Open remote connectivity on your computer via SSH:

![](https://cdn-images-1.medium.com/max/2588/0*9SERuGyLfqoTK4WW.png)

ssh -i "ebs-ssh-key.pem" ec2-user@[ec2-52-201-156-146.compute-1.amazonaws.com](http://ec2-52-201-156-146.compute-1.amazonaws.com)

![](https://cdn-images-1.medium.com/max/4184/0*MHY1wz-AzqD4093u.png)

Install the stress tool to perform the load testing:

    sudo amazon-linux-extras install epel -y
    sudo yum install stress -y
    stress -c 4

This comment is going to bump up the CPU utilization inside the EC2 instance. Check Elastic Beanstalk status if it is turned “Warning”. Stress command bumping CPU utilization of this instance 100 %. We configured it as if CPU utilization is higher than 50%, the auto-scaling group will add one new instance so we can keep up with the workload.

![](https://cdn-images-1.medium.com/max/4124/0*8W4sCLRyBdF68PNn.png)

Open a new terminal, connect remotely with SSH again, and use the “top” command that shows CPU utilization on the operating system.

![](https://cdn-images-1.medium.com/max/3496/0*Dklh_WwBdjhHg9mB.png)

New instances will be added shortly to scale up. Every single user who goes through the load balancer will be redirected to one of these instances.

![](https://cdn-images-1.medium.com/max/3764/0*aqenaqbHLB6-0eZt.png)

![](https://cdn-images-1.medium.com/max/4396/0*8bwQqhKPtqRa877R.png)

Stop the loading process and end up stress command and check the process is not running anymore by running the command below:

    Ctrl + C
    ps -ef | grep stress

The stress is running anymore so the health status will change to OK. The auto scale will scale down and remove 3rd instance added before, so we can save cost.

Once you finish exploring it, please remove the Elastic Beanstalk application, and Elastic Beanstalk environment, disable and delete the CloudFront distribution, and finally delete the DynamoDB users table.

CONGRATULATIONS!!!

**REFERENCES**

[Elastic Beanstalk service role](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts-roles-service.html)

[AWS Elastic Beanstalk Developer Guide](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html)

[AWS-Deploying a Flask application to Elastic Beanstal](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html)k

[Deploying a Flask Application to Elastic Beanstalk](https://testdriven.io/blog/flask-elastic-beanstalk/)

[Elastic Beanstalk-supported platforms](https://docs.aws.amazon.com/elasticbeanstalk/latest/platforms/platforms-supported.html#platforms-supported.python)

[No module named ‘application’ Error while deploying a simple web app to Elastic Beanstalk](https://stackoverflow.com/questions/62479386/no-module-named-application-error-while-deploying-simple-web-app-to-elastic-be)

[WSGI configuration for Django Deployment using EB CLI](https://repost.aws/questions/QUcm3GAgnESN2wCOtD-hqzsQ/wsgi-configuration-for-django-deployment-using-eb-cli)

[Create an application source bundle](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/applications-sourcebundle.html)

[What is AWS Elastic Beanstalk?](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html)

[Deploy a sample web application using Elastic Beanstalk](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/GettingStarted.html)

[Install the EB CLI](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html)

[AWS security credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-creds.html)

[EBS configuration options for all environments](https://docs.aws.amazon.com/pdfs/elasticbeanstalk/latest/dg/awseb-dg.pdf#command-options-general)