Lab 2: Reliability
© 2023 Amazon Web Services, Inc. or its affiliates. All rights reserved. This work may not be reproduced or redistributed, in whole or in part, without prior written permission from Amazon Web Services, Inc. Commercial copying, lending, or selling is prohibited. All trademarks are the property of their owners.
Note: Do not include any personal, identifying, or confidential information into the lab environment. Information entered may be visible to others.
Corrections, feedback, or other questions? Contact us at AWS Training and Certification.
Objectives
This hands-on lab will guide you through the steps to improve reliability of a service by using automation to deploy a reliable cloud infrastructure. You will create additional subnets in a second Availability Zone, setup Elastic Load Balancing (ELB), and an Amazon EC2 Auto Scaling group for the web application, applying the Scale horizontally to increase aggregate workload availability design principle from the AWS Well-Architected Framework. You also migrate the database to Amazon Relational Database Service (Amazon RDS) to make use of an multiple Availability Zone deployment. When your architecture is ready, you will test it to ensure that your implementation is resilient to failure, applying the test recovery procedures design principle.
After completing this lab, you will be able to:
Expand an existing architecture to a second Availability Zone.
Add subnets to an Availability Zone.
Deploy Amazon RDS using a multiple Availability Zones configuration.
Update Parameter Store, a capability of AWS Systems Manager, for database credentials.
Create an Application Load Balancer and a target group.
Migrate a database from a standalone instance to Amazon RDS using Systems Manager Run Command.
Create a launch template.
Create an Amazon EC2 Auto Scaling group.
Create Amazon Route 53 health checks.
Test your application reliability by terminating instances from the AWS Auto Scaling group.
PREREQUISITES
This lab requires:
Use of a personal computer or laptop with Wi-Fi. The lab is not accessible using an iPad or tablet device, but you can use these devices to access the student guide.
Access to the administrator account on your local the computer.
Access to an internet browser, such as Chrome or Firefox.
ICON KEY
Various icons are used throughout this lab to call attention to different types of instructions and notes. The following list explains the purpose for each icon:
Command: A command that you must run.
Expected output: A sample output that you can use to verify the output of a command or edited file.
Note: A hint, tip, or important guidance.
Additional information: Where to find more information.
CAUTION: Information of special interest or importance (not so important to cause problems with the equipment or data if you miss it, but it could result in the need to repeat certain steps).
WARNING: An action that is irreversible and could potentially impact the failure of a command or process (including warnings about configurations that cannot be changed after they are made).
DURATION
This lab requires 60 minutes to complete.
SCENARIO
During the AWS Well-Architected Framework Review you learned how important it is to build a resilient solution to protect against failure. You understood the risks and business impact in case of failure.
ARCHITECTURE
The architecture of the infrastructure you deploy by the end of the lab is diagrammed below:
The architecture is an Amazon VPC containing 2 Availability Zones. There are 6 total subnets in the environment, with each Availability Zone having 3 of the subnets. The subnets are labelled and divided per Availability Zone as such: 1 public subnet, 1 private subnet, and 1 db private subnet. Each of the private subnets is part of an Amazon EC2 Auto Scaling group and contains 1 web server each. Each of the db private subnets contain 1 Amazon RDS instance each. Internet traffic flows into an internet gateway, to an Application Load Balancer residing in the public subnets, then to the Amazon EC2 Auto Scaling group in the private subnets, and finally to the Amazon RDS primary instance in the db private subnet. Supporting management, automation & monitoring services for the environment are: Amazon CloudWatch and AWS Systems Manager. Supporting security services for the environment are AWS Identity and Access Management, and AWS Secrets Manager.
Start lab
- To launch the lab, at the top of the page, choose Start lab.
You must wait for the provisioned AWS services to be ready before you can continue.
- To open the lab, choose Open Console.
You are automatically signed in to the AWS Management Console in a new web browser tab.
Do not change the Region unless instructed.
COMMON SIGN-IN ERRORS
Error: You must first sign out
If you see the message, You must first log out before logging into a different AWS account:
Choose the click here link.
Close your Amazon Web Services Sign In web browser tab and return to your initial lab page.
Choose Open Console again.
Error: Choosing Start Lab has no effect
In some cases, certain pop-up or script blocker web browser extensions might prevent the Start Lab button from working as intended. If you experience an issue starting the lab:
Add the lab domain name to your pop-up or script blocker’s allow list or turn it off.
Refresh the page and try again.
Task 1: Add Subnets to a Second Availability Zone
The architecture provided at the start of this task is diagrammed as follows:
The architecture contains a single Amazon VPC, which has an internet gateway and 2 subnets in a single Availability Zone. The subnets are labelled: public subnet, and private subnet. The public subnet contains two Amazon EC2 instances. One instance is labelled as web app instance and the other instance is labelled as shell server instance. The private subnet contains one subnet labelled as database instance.
In this task, you create two additional subnets in a second Availability Zone to improve application reliability. Availability for applications can improve by using two or more Availability Zones for deployment and by decoupling the applications and dividing the tiers.
In this lab, you use services that work across multiple Availability Zones, such as: Elastic Load Balancing, Amazon EC2 Auto Scaling, and Multi-AZ Amazon RDS. This architecture is fault tolerant on the individual resource level and on the Availability Zone level.
After performing the steps in this task, the architecture resembles the following diagram:
The architecture contains a single Amazon VPC, which has an internet gateway and 4 subnets divided across two Availability Zones. 2 of the subnets are labelled as public subnet and 2 of the subnets are labelled as private subnet. The public subnet in the first Availability Zone contains 2 Amazon EC2 instances. One of the instances is web app instance, and the other is labelled as shell server instance. The private subnet has one Amazon EC2 instance labelled as database instance. The subnets in the second Availability Zone do not have any Amazon EC2 instances. Internet traffic flows into the internet gateway to the web app instance.
Note: Even though you can create subnets, Elastic Load Balancing, Amazon EC2 Auto Scaling groups and other application components using the AWS Console, in this lab you take advantage of the benefits of automation using commands in the AWS Command Line Interface (AWS CLI.
Throughout this lab you use the terminal in a provided Amazon Elastic Compute Cloud (Amazon EC2) instance called .
If you remain idle for a long period of time, the shell in your browser might become unresponsive. In this case, refresh the browser page.
You use Amazon EC2 Instance Connect from the Amazon EC2 instances dashboard page to access the shell.
At the top of the AWS Management Console, in the search bar, search for and choose
.
On the navigation menu at the left of the page, under Instances, choose Instances.
In the instances list, select the checkbox next to the wa-shell-server instance only.
Choose Connect at the top.
The browser displays the Connect to instance page.
Select the EC2 Instance Connect tab.
Choose Connect.
A terminal is displayed in the browser.
Note: Remember these actions because you might need to repeat them if the terminal becomes unresponsive and enters a timeout state.
- In the terminal, install the package . This substitutes shell format strings with environment variables in text and is needed for this lab.
Command:
sudo yum install gettext -y
Expected output: if the package is already installed, the expected output returned to the terminal is as follows:
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Package gettext-0.19.8.1-3.amzn2.x86_64 already installed and latest version
Nothing to do
- Set the AWS account number as an environment variable.
Command:
export awsAccount=`aws sts get-caller-identity --query "Account" --output text` && echo awsAccount=$awsAccount >> ~/.bashrc
The command line returns to a new prompt when complete.
- Query instance metadata and set the AWS Region of the Amazon EC2 instance as an environment variable.
Command:
export awsRegion=`curl -s http://169.254.169.254/latest/meta-data/placement/region` && echo awsRegion=$awsRegion >> ~/.bashrc
The command line returns to a new prompt when complete.
- Set the virtual private cloud (VPC) ID as an environment variable.
Command:
export VPC=`aws ec2 describe-vpcs --filters Name=tag:Name,Values=wa-lab-vpc --query 'Vpcs[*].VpcId' --output text --region $awsRegion` && echo VPC=$VPC >> ~/.bashrc
The command line returns to a new prompt when complete.
The first Availability Zone is where the Amazon EC2 instances reside at the start of this lab.
- Set an environment variable for the first Availability Zone in the AWS Region.
Command:
export awsAZ1=`aws ec2 describe-availability-zones --region $awsRegion --query 'AvailabilityZones[].ZoneName[]|[0]' --output text` && echo awsAZ1=$awsAZ1 >> ~/.bashrc
The command line returns to a new prompt when complete.
The second Availability Zone is where you expand the architecture to in this lab.
- Set an environment variable for the second Availability Zone in the AWS Region.
Command:
export awsAZ2=`aws ec2 describe-availability-zones --region $awsRegion --query 'AvailabilityZones[].ZoneName[]|[1]' --output text` && echo awsAZ2=$awsAZ2 >> ~/.bashrc
The command line returns to a new prompt when complete.
- Create a public subnet in the second Availability Zone.
Command:
aws ec2 create-subnet --vpc-id $VPC --cidr-block "10.100.2.0/24" --availability-zone $awsAZ2 --tag-specifications 'ResourceType=subnet, Tags=[{Key=Name,Value=wa-public-subnet-2}]' --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Subnet": {
"MapPublicIpOnLaunch": false,
"AvailabilityZoneId": "usw2-az1",
"Tags": [
{
"Value": "wa-public-subnet-2",
"Key": "Name"
}
],
"AvailableIpAddressCount": 251,
"DefaultForAz": false,
"SubnetArn": "arn:aws:ec2:us-west-2:046369250458:subnet/subnet-0010689897378bde5",
"Ipv6CidrBlockAssociationSet": [],
"VpcId": "vpc-0b187d1840dbaf354",
"State": "available",
"AvailabilityZone": "us-west-2b",
"SubnetId": "subnet-0010689897378bde5",
"OwnerId": "046369250458",
"CidrBlock": "10.100.2.0/24",
"AssignIpv6AddressOnCreation": false
}
}
- Create a private subnet in the second Availability Zone.
Command:
aws ec2 create-subnet --vpc-id $VPC --cidr-block "10.100.3.0/24" --availability-zone $awsAZ2 --tag-specifications 'ResourceType=subnet, Tags=[{Key=Name,Value=wa-private-subnet-2}]' --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Subnet": {
"MapPublicIpOnLaunch": false,
"AvailabilityZoneId": "usw2-az1",
"Tags": [
{
"Value": "wa-private-subnet-2",
"Key": "Name"
}
],
"AvailableIpAddressCount": 251,
"DefaultForAz": false,
"SubnetArn": "arn:aws:ec2:us-west-2:046369250458:subnet/subnet-0f90815893c56d1a4",
"Ipv6CidrBlockAssociationSet": [],
"VpcId": "vpc-0b187d1840dbaf354",
"State": "available",
"AvailabilityZone": "us-west-2b",
"SubnetId": "subnet-0f90815893c56d1a4",
"OwnerId": "046369250458",
"CidrBlock": "10.100.3.0/24",
"AssignIpv6AddressOnCreation": false
}
}
- Add the new public subnet as an environment variable.
Command:
export publicSubnetId=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-public-subnet-2 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo publicSubnetId=$publicSubnetId >> ~/.bashrc
The command line returns to a new prompt when complete.
- Add the new private subnet as an environment variable.
Command:
export privateSubnetId=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-private-subnet-2 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo privateSubnetId=$privateSubnetId >> ~/.bashrc
The command line returns to a new prompt when complete.
- Add the existing public route table as an environment variable.
Command:
export publicRt=`aws ec2 describe-route-tables --filters Name=tag:Name,Values=wa-public-rt --query 'RouteTables[*].RouteTableId' --output text --region $awsRegion` && echo publicRt=$publicRt >> ~/.bashrc
The command line returns to a new prompt when complete.
- Add the existing private route table as an environment variable.
Command:
export privateRt=`aws ec2 describe-route-tables --filters Name=tag:Name,Values=wa-private-rt --query 'RouteTables[*].RouteTableId' --output text --region $awsRegion` && echo privateRt=$privateRt >> ~/.bashrc
The command line returns to a new prompt when complete.
- Associate the existing public route table with the public subnet created in the second Availability Zone.
Command:
aws ec2 associate-route-table --subnet-id $publicSubnetId --route-table-id $publicRt --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"AssociationState": {
"State": "associated"
},
"AssociationId": "rtbassoc-0ee7fdb070e896e58"
}
- Associate the existing private route table with the private subnet created in the second Availability Zone.
Command:
aws ec2 associate-route-table --subnet-id $privateSubnetId --route-table-id $privateRt --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"AssociationState": {
"State": "associated"
},
"AssociationId": "rtbassoc-0368cc8685702d546"
}
Congratulations! In this task you, created new subnets in a second Availability Zone. You also created environment variables for the following: VPC ID, AWS account ID, Availability Zones, public and private subnets, and public and private route tables. Finally, you associated the new subnets in the second Availability Zone with existing route tables.
Task 2: Deploying Amazon RDS Using Multiple Availability Zones
In this task, you complete the steps needed for creating an Amazon Relational Database Service (Amazon RDS) for MariaDB Multi-AZ deployment. This deployment provides enhanced availability and durability for Amazon RDS database instances, making them a natural fit for production database workloads. When you provision a Multi-AZ database instance, Amazon RDS automatically creates a primary database instance and synchronously replicates the data to a standby instance in a different Availability Zone (AZ).
Note: Your database is not currently configured for high availability. The objective is to improve reliability for the application components of the architecture, which includes the database. You use the Multi-AZ deployment to migrate the original database to a Multi-AZ architecture.
After performing the steps in this task, the architecture resembles the following diagram:
The architecture is an Amazon VPC containing 2 Availability Zones. There are 6 total subnets in the environment, with each Availability Zone having 3 of the subnets. The subnets are labelled and divided per Availability Zone as such: 1 public subnet, 1 private subnet, and 1 db private subnet. The public subnet in the first Availability Zone contains 2 Amazon EC2 instances. One of the instances is web app instance, and the other is labelled as shell server instance. The private subnet has one Amazon EC2 instance labelled as database instance. Each of the db private subnets contain 1 Amazon RDS instance each. Internet traffic flows into an internet gateway, to the web app instance and finally to the database instance.
- Create Amazon RDS subnets in the first Availability Zone.
Command:
aws ec2 create-subnet --vpc-id $VPC --cidr-block "10.100.4.0/24" --availability-zone $awsAZ1 --tag-specifications 'ResourceType=subnet, Tags=[{Key=Name,Value=wa-rds-subnet-1}]' --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Subnet": {
"MapPublicIpOnLaunch": false,
"AvailabilityZoneId": "usw2-az2",
"Tags": [
{
"Value": "wa-rds-subnet-1",
"Key": "Name"
}
],
"AvailableIpAddressCount": 251,
"DefaultForAz": false,
"SubnetArn": "arn:aws:ec2:us-west-2:046369250458:subnet/subnet-0c12a49c53b7a160b",
"Ipv6CidrBlockAssociationSet": [],
"VpcId": "vpc-0b187d1840dbaf354",
"State": "available",
"AvailabilityZone": "us-west-2a",
"SubnetId": "subnet-0c12a49c53b7a160b",
"OwnerId": "046369250458",
"CidrBlock": "10.100.4.0/24",
"AssignIpv6AddressOnCreation": false
}
}
- Create Amazon RDS subnets in the second Availability Zone.
Command:
aws ec2 create-subnet --vpc-id $VPC --cidr-block "10.100.5.0/24" --availability-zone $awsAZ2 --tag-specifications 'ResourceType=subnet, Tags=[{Key=Name,Value=wa-rds-subnet-2}]' --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Subnet": {
"MapPublicIpOnLaunch": false,
"AvailabilityZoneId": "usw2-az1",
"Tags": [
{
"Value": "wa-rds-subnet-2",
"Key": "Name"
}
],
"AvailableIpAddressCount": 251,
"DefaultForAz": false,
"SubnetArn": "arn:aws:ec2:us-west-2:046369250458:subnet/subnet-07e6320b354495aa7",
"Ipv6CidrBlockAssociationSet": [],
"VpcId": "vpc-0b187d1840dbaf354",
"State": "available",
"AvailabilityZone": "us-west-2b",
"SubnetId": "subnet-07e6320b354495aa7",
"OwnerId": "046369250458",
"CidrBlock": "10.100.5.0/24",
"AssignIpv6AddressOnCreation": false
}
}
- Add the first of the new Amazon RDS subnets as an environment variable.
Command:
export rdsSubnet1Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-rds-subnet-1 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo rdsSubnet1Id=$rdsSubnet1Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Add the second of the new Amazon RDS subnets as an environment variable.
Command:
export rdsSubnet2Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-rds-subnet-2 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo rdsSubnet2Id=$rdsSubnet2Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Associate the first Amazon RDS subnet with the private route table.
Command:
aws ec2 associate-route-table --subnet-id $rdsSubnet1Id --route-table-id $privateRt --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"AssociationState": {
"State": "associated"
},
"AssociationId": "rtbassoc-053c5775904f5502f"
}
- Associate the second Amazon RDS subnet with the private route table.
Command:
aws ec2 associate-route-table --subnet-id $rdsSubnet2Id --route-table-id $privateRt --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"AssociationState": {
"State": "associated"
},
"AssociationId": "rtbassoc-0a7ac463011a4e4c7"
}
- Create an Amazon RDS subnet group using both of the new Amazon RDS subnets.
Command:
aws rds create-db-subnet-group --db-subnet-group-name "wa-rds-subnet-group" --db-subnet-group-description "WA RDS Subnet Group" --subnet-ids $rdsSubnet1Id $rdsSubnet2Id --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"DBSubnetGroup": {
"Subnets": [
{
"SubnetStatus": "Active",
"SubnetIdentifier": "subnet-07e6320b354495aa7",
"SubnetOutpost": {},
"SubnetAvailabilityZone": {
"Name": "us-west-2b"
}
},
{
"SubnetStatus": "Active",
"SubnetIdentifier": "subnet-0c12a49c53b7a160b",
"SubnetOutpost": {},
"SubnetAvailabilityZone": {
"Name": "us-west-2a"
}
}
],
"VpcId": "vpc-0b187d1840dbaf354",
"DBSubnetGroupDescription": "WA RDS Subnet Group",
"SubnetGroupStatus": "Complete",
"DBSubnetGroupArn": "arn:aws:rds:us-west-2:046369250458:subgrp:wa-rds-subnet-group",
"DBSubnetGroupName": "wa-rds-subnet-group"
}
}
- Create an IAM security group for Amazon RDS to use.
Command:
aws ec2 create-security-group --description "RDS Security group" --group-name "wa-rds-sg" --vpc-id $VPC --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"GroupId": "sg-000e0b58bccba46d7"
}
- Set the Amazon RDS security group ID as an environment variable.
Command:
export rdsSg=`aws ec2 describe-security-groups --filters Name=group-name,Values=wa-rds-sg --query 'SecurityGroups[*].GroupId' --output text --region $awsRegion` && echo rdsSg=$rdsSg >> ~/.bashrc
The command line returns to a new prompt when complete.
- Set a environment variable for the second IAM security group ID, used by the Amazon EC2 database instance.
Command:
export ec2DbSg=`aws ec2 describe-security-groups --filters Name=group-name,Values=wa-database-sg --query 'SecurityGroups[*].GroupId' --output text --region $awsRegion` && echo ec2DbSg=$ec2DbSg >> ~/.bashrc
The command line returns to a new prompt when complete.
- Allow the Amazon RDS security group to communicate with the security group used by the Amazon EC2 database instance.
Command:
aws ec2 authorize-security-group-ingress --group-id $rdsSg --source-group $ec2DbSg --protocol "tcp" --port "3306" --region $awsRegion
The command line returns to a new prompt when complete.
- Create a Multi-AZ Amazon RDS instance.
Command:
aws rds create-db-instance --db-name "WaRdsDb" --db-instance-identifier "waDbInstance" --allocated-storage 20 --db-instance-class db.t3.micro --engine "mariadb" --master-username "mainuser" --master-user-password "WaStr0ngP4ssw0rd" --vpc-security-group-ids $rdsSg --db-subnet-group-name "wa-rds-subnet-group" --multi-az --no-publicly-accessible --backup-retention-period 0 --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"DBInstance": {
"PubliclyAccessible": false,
"MasterUsername": "mainuser",
"MonitoringInterval": 0,
"LicenseModel": "general-public-license",
"VpcSecurityGroups": [
{
"Status": "active",
"VpcSecurityGroupId": "sg-000e0b58bccba46d7"
}
],
"CopyTagsToSnapshot": false,
"OptionGroupMemberships": [
{
"Status": "in-sync",
"OptionGroupName": "default:mariadb-10-6"
}
],
"PendingModifiedValues": {
"MasterUserPassword": "****"
},
"Engine": "mariadb",
"MultiAZ": true,
"DBSecurityGroups": [],
"DBParameterGroups": [
{
"DBParameterGroupName": "default.mariadb10.6",
"ParameterApplyStatus": "in-sync"
}
],
"PerformanceInsightsEnabled": false,
"AutoMinorVersionUpgrade": true,
"PreferredBackupWindow": "08:37-09:07",
"DBSubnetGroup": {
"Subnets": [
{
"SubnetStatus": "Active",
"SubnetIdentifier": "subnet-07e6320b354495aa7",
"SubnetOutpost": {},
"SubnetAvailabilityZone": {
"Name": "us-west-2b"
}
},
{
"SubnetStatus": "Active",
"SubnetIdentifier": "subnet-0c12a49c53b7a160b",
"SubnetOutpost": {},
"SubnetAvailabilityZone": {
"Name": "us-west-2a"
}
}
],
"DBSubnetGroupName": "wa-rds-subnet-group",
"VpcId": "vpc-0b187d1840dbaf354",
"DBSubnetGroupDescription": "WA RDS Subnet Group",
"SubnetGroupStatus": "Complete"
},
"ReadReplicaDBInstanceIdentifiers": [],
"AllocatedStorage": 20,
"DBInstanceArn": "arn:aws:rds:us-west-2:046369250458:db:wadbinstance",
"BackupRetentionPeriod": 0,
"DBName": "WaRdsDb",
"PreferredMaintenanceWindow": "sun:11:16-sun:11:46",
"DBInstanceStatus": "creating",
"IAMDatabaseAuthenticationEnabled": false,
"EngineVersion": "10.6.10",
"DeletionProtection": false,
"DomainMemberships": [],
"StorageType": "gp2",
"DbiResourceId": "db-TJWGNSZOSLANNDJPUHQM6HXUSY",
"CACertificateIdentifier": "rds-ca-2019",
"StorageEncrypted": false,
"AssociatedRoles": [],
"DBInstanceClass": "db.t3.micro",
"DbInstancePort": 0,
"DBInstanceIdentifier": "wadbinstance"
}
}
Note: The previous command creates an Amazon RDS database instance with the following configuration:
Key | Value |
Identifier | waDbInstance |
Engine | MariaDB |
DB instance type | db.t3.micro |
Storage | 20 GB |
Multi-AZ | Yes |
Publicly accessible | No |
Note: If after running the previous command, there is a : at the bottom of the screen. Type q to quit the process and continue using the shell for the subsequent steps. The Multi-AZ Amazon RDS creation process will continue.
Note: Multi-AZ RDS creation takes 10-15 minutes. Go ahead and continue with the next task.
Congratulations! In this task, you created the necessary Amazon RDS network infrastructure for your environment and deployed an Amazon RDS database with a Multi-AZ configuration.
Task 3: Update the AWS Systems Manager Parameter Store Database
The first step in this task is to validate if the Amazon RDS instance URL endpoint is already available. This can take up to 4 minutes after the Amazon RDS instance creation command.
- Run the following command to confirm if the Amazon RDS endpoint is available:
Command:
aws rds describe-db-instances --db-instance-identifier "waDbInstance" --query 'DBInstances[*].Endpoint.Address' --output text --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
wadbinstance.cyk7pychnesl.us-west-2.rds.amazonaws.com
WARNING: If the output of the previous command is null or empty, please wait a minute and try again. After you get the endpoint URL as the command output, continue with the next lab steps.
- Update the AWS Systems Manager values in Parameter Store.
First, validate the value, stored in Parameter Store, that the application is using to point to the application database installed on the Amazon EC2 instance (the original database).
Command:
aws ssm get-parameters --names "DbPrivateDns" --region $awsRegion --output table
Expected output: A sample of output returned to the terminal is as follows:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| GetParameters |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|| Parameters ||
|+------------------------------------------------------------+-----------+-------------------+---------------+---------+----------------------------------------------+----------+|
|| ARN | DataType | LastModifiedDate | Name | Type | Value | Version ||
|+------------------------------------------------------------+-----------+-------------------+---------------+---------+----------------------------------------------+----------+|
|| arn:aws:ssm:us-west-2:046369250458:parameter/DbPrivateDns | text | 1668459546.39 | DbPrivateDns | String | ip-10-100-1-252.us-west-2.compute.internal | 1 ||
|+------------------------------------------------------------+-----------+-------------------+---------------+---------+----------------------------------------------+----------+|
- Find the value under the Value column. This is the Amazon EC2 database server’s private Domain Name System (DNS) name.
Now, update this parameter value with the Amazon RDS endpoint. Application instances in the AWS Auto Scaling group use this endpoint during their bootstrapping process.
- Set the Amazon RDS endpoint as an environment variable.
Command:
export rdsEndPoint=`aws rds describe-db-instances --db-instance-identifier "waDbInstance" --query 'DBInstances[*].Endpoint.Address' --output text --region $awsRegion` && echo rdsEndPoint=$rdsEndPoint >> ~/.bashrc
The command line returns to a new prompt when complete.
- Update the Parameter Store value to point to the Amazon RDS endpoint.
Command:
aws ssm put-parameter --name "DbPrivateDns" --value $rdsEndPoint --overwrite --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Tier": "Standard",
"Version": 2
}
- Run the following command to validate that Parameter Store has been updated with the Amazon RDS endpoint.
Command:
aws ssm get-parameters --names "DbPrivateDns" --output table --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
-------------------------------------------------------------------------------------
| GetParameters |
+-----------------------------------------------------------------------------------+
|| Parameters ||
|+------------------+--------------------------------------------------------------+|
|| ARN | arn:aws:ssm:us-west-2:046369250458:parameter/DbPrivateDns ||
|| DataType | text ||
|| LastModifiedDate| 1668468125.31 ||
|| Name | DbPrivateDns ||
|| Type | String ||
|| Value | wadbinstance.cyk7pychnesl.us-west-2.rds.amazonaws.com ||
|| Version | 2 ||
|+------------------+--------------------------------------------------------------+|
Congratulations! In this task, you set the Amazon RDS endpoint as a database value for the application architecture in Parameter Store.
Task 4: Create an Application Load Balancer and a Target Group
The Elastic Load Balancing (ELB) service in this lab is used to provide a single access point for clients. The Application Load Balancer distributes incoming application traffic across multiple targets, such as Amazon EC2 instances, in multiple Availability Zones. This increases the availability of your application.
In this task, you create a type of load balancer called an Application Load Balancer (ALB) and a target group that is used to configure an AWS EC2 Auto Scaling group later in this lab.
After performing steps in this task, the architecture resembles the following diagram:
The architecture is an Amazon VPC containing 2 Availability Zones and Elastic Load Balancing. There are 6 total subnets in the environment, with each Availability Zone having 3 of the subnets. The subnets are labelled and divided per Availability Zone as such: 1 public subnet, 1 private subnet, and 1 db private subnet. The public subnet in the first Availability Zone contains 2 Amazon EC2 instances. One of the instances is web app instance, and the other is labelled as shell server instance. The private subnet has one Amazon EC2 instance labelled as database instance. Each of the db private subnets contain 1 Amazon RDS instance each. Internet traffic flows into the Application Load Balancer.
- Create a security group for the Application Load Balancer.
Command:
aws ec2 create-security-group --description "ALB Security group" --group-name "wa-alb-sg" --vpc-id $VPC --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"GroupId": "sg-0a1305f60b790422b"
}
- Set the Application Load Balancer security group as an environmental variable.
Command:
export albSg=`aws ec2 describe-security-groups --filters Name=group-name,Values=wa-alb-sg --query 'SecurityGroups[*].GroupId' --output text --region $awsRegion` && echo albSg=$albSg >> ~/.bashrc
The command line returns to a new prompt when complete.
- Allow HTTP access through the Application Load Balancer security group.
Command:
aws ec2 authorize-security-group-ingress --group-id $albSg --protocol "tcp" --port "80" --cidr "0.0.0.0/0" --region $awsRegion
The command line returns to a new prompt when complete.
- Set the first public subnet the Application Load Balancer will use as an environment variable.
Command:
export albSubnet1Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-public-subnet-1 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo albSubnet1Id=$albSubnet1Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Set the second public subnet the Application Load Balancer will use as an environment variable.
Command:
export albSubnet2Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-public-subnet-2 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo albSubnet2Id=$albSubnet2Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Create an Application Load Balancer.
Command:
aws elbv2 create-load-balancer --name "waAlb" --subnets $albSubnet1Id $albSubnet2Id --security-groups $albSg --type "application" --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"LoadBalancers": [
{
"IpAddressType": "ipv4",
"VpcId": "vpc-0b187d1840dbaf354",
"LoadBalancerArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:loadbalancer/app/waAlb/fce5084a8c1e328f",
"State": {
"Code": "provisioning"
},
"DNSName": "waAlb-816446507.us-west-2.elb.amazonaws.com",
"SecurityGroups": [
"sg-0a1305f60b790422b"
],
"LoadBalancerName": "waAlb",
"CreatedTime": "2022-11-15T16:49:45.720Z",
"Scheme": "internet-facing",
"Type": "application",
"CanonicalHostedZoneId": "Z1H1FL5HABSF5",
"AvailabilityZones": [
{
"SubnetId": "subnet-0010689897378bde5",
"LoadBalancerAddresses": []
},
{
"SubnetId": "subnet-056c0c0da9a41b3aa",
"LoadBalancerAddresses": []
}
]
}
]
}
- Create a target group.
Command:
aws elbv2 create-target-group --name "waAutoscale-tg" --protocol "HTTP" --port 80 --vpc-id $VPC --target-type "instance" --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"TargetGroups": [
{
"HealthCheckPath": "/",
"HealthCheckIntervalSeconds": 30,
"VpcId": "vpc-0b187d1840dbaf354",
"Protocol": "HTTP",
"HealthCheckTimeoutSeconds": 5,
"TargetType": "instance",
"HealthCheckProtocol": "HTTP",
"Matcher": {
"HttpCode": "200"
},
"UnhealthyThresholdCount": 2,
"HealthyThresholdCount": 5,
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:targetgroup/waAutoscale-tg/e0a430a5a64c46aa",
"HealthCheckEnabled": true,
"HealthCheckPort": "traffic-port",
"Port": 80,
"TargetGroupName": "waAutoscale-tg"
}
]
}
- Set the target group as an environment variable.
Command:
export waTg=`aws elbv2 describe-target-groups --names waAutoscale-tg --query 'TargetGroups[*].TargetGroupArn' --output text --region $awsRegion` && echo waTg=$waTg >> ~/.bashrc
The command line returns to a new prompt when complete.
- Set the Amazon Resource Name (ARN) for the Application Load Balancer as an environment variable.
Command:
export albArn=`aws elbv2 describe-load-balancers --names waAlb --query 'LoadBalancers[*].LoadBalancerArn' --output text --region $awsRegion` && echo albArn=$albArn >> ~/.bashrc
The command line returns to a new prompt when complete.
- Download a template listener.json file to the shell instance.
Command:
cd ~
wget https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/listener-source.json
Expected output: A sample of output returned to the terminal is as follows:
--2022-11-15 16:56:27-- https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/listener-source.json
Resolving aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)... 3.5.83.115, 3.5.80.14, 52.218.136.161, ...
Connecting to aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)|3.5.83.115|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 96 [application/json]
Saving to: ‘listener-source.json’
100%[=============================================================================================================================================>] 96 --.-K/s in 0s
2022-11-15 16:56:27 (4.87 MB/s) - ‘listener-source.json’ saved [96/96]
- Replace environment variables in the template with the target group and create a new template file.
Command:
envsubst < "listener-source.json" > "listener.json"
The command line returns to a new prompt when complete.
Note: If you receive the following error: bash: envsubst: command not found this is because the envsubst module dependency is not installed. In this case, run this command again:
- Create a listener for the Application Load Balancer, referencing the template file.
Command:
aws elbv2 create-listener --load-balancer-arn $albArn --protocol "HTTP" --port 80 --default-actions file://listener.json --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"Listeners": [
{
"Protocol": "HTTP",
"DefaultActions": [
{
"ForwardConfig": {
"TargetGroupStickinessConfig": {
"Enabled": false
},
"TargetGroups": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:targetgroup/waAutoscale-tg/e0a430a5a64c46aa",
"Weight": 1
}
]
},
"TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:targetgroup/waAutoscale-tg/e0a430a5a64c46aa",
"Type": "forward",
"Order": 1
}
],
"LoadBalancerArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:loadbalancer/app/waAlb/fce5084a8c1e328f",
"Port": 80,
"ListenerArn": "arn:aws:elasticloadbalancing:us-west-2:046369250458:listener/app/waAlb/fce5084a8c1e328f/8707ac39be0e2dea"
}
]
}
Congratulations! In this task, you created and configured a new target group, a listener on port 80, and a new Application Load Balancer for your environment to use.
Task 5: Database Migration with AWS Systems Manager Run Command
In this task, you migrate the application database from the Amazon EC2 instance to the Amazon RDS for MariaDB Multi-AZ deployment. You perform this activity using the Run command tool from AWS Systems Manager.
Note: Before starting this migration task, populate data in your database.
To the left of these instructions, copy the ApplicationPublicDns value provided. Open a new tab in your web browser and paste the ApplicationPublicDns value as the URL. The application is loaded in the web browser.
To add a product to the database, perform the following steps:
Enter a value in the Category field.
Enter a value in the Description field.
Enter a value in the Price field.
Choose the Update database button to insert the item.
- Add at least three products to the list. When complete, leave this browser window open for future reference.
The app contains entry fields labelled as: Category, description and price. There is a button labelled update database. And there is a data table at the bottom of the page. The data table contains 3 examples.
Return to the browser tab with the terminal. You might need to refresh the page if the terminal is timed out and unresponsive.
Confirm the Amazon RDS instance is fully deployed and running the following command; confirm the status is available before continuing.
Command:
aws rds describe-db-instances --db-instance-identifier "waDbInstance" --query 'DBInstances[*].{DB_Identifier:DBInstanceIdentifier,Status:DBInstanceStatus}' --output table --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
--------------------------------
| DescribeDBInstances |
+----------------+-------------+
| DB_Identifier | Status |
+----------------+-------------+
| wadbinstance | available |
+----------------+-------------+
WARNING: If the status is creating or modifying, please rerun the previous command every 1 or 2 minutes until the status is available. Then, you can continue.
Return to the AWS Management Console.
At the top of the AWS Management Console, in the search bar, search for and choose
.
On the navigation menu at the left of the page, under Node Management, choose Run Command.
The browser displays the Run Command page.
- Choose Run Command.
Note: If the first-time use Landing page is displayed instead of the Commands page, choose Run a Command in the Manage your instances section.
The browser displays the Run a command page.
In the Command document search box, input , and then press Enter.
Select AWS-RunShellScript from the list of returned results.
Caution: Make sure that you select the radio switch and not the link for the command document itself. Selecting the link for the command document will display details about the command document, which is the wrong page for this step.
- On the Run a command page, in the Command parameters section, paste the following script.
Command:
#!/bin/bash
# Database backup using mysqldump utility
mysqldump sample > backup.sql
# Add RDS endpoint as an environment variable
export awsRegion=`curl -s http://169.254.169.254/latest/meta-data/placement/region`
export rdsendpoint=`aws ssm get-parameter --name DbPrivateDns --query 'Parameter.Value' --region $awsRegion --output text`
# Set RDS instance admin user variable
export user=mainuser
# Set the RDS admin password value stored in Secrets Manager as variable
export rdspasswd=`aws secretsmanager get-secret-value --secret-id rdsPassword --query 'SecretString' --output text --region $awsRegion`
# Below commands creates database, loads MySQL backup into RDS, creates a user and set permissions in RDS database instance
mysql -h $rdsendpoint -u $user -p$rdspasswd -e "CREATE DATABASE sample;"
mysql -h $rdsendpoint -u $user -p$rdspasswd -e "USE sample;source backup.sql;"
mysql -h $rdsendpoint -u $user -p$rdspasswd -e "CREATE USER 'tutorial_user'@'%' IDENTIFIED BY 'WaFram3w0rk';"
mysql -h $rdsendpoint -u $user -p$rdspasswd -e "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'tutorial_user'@'%' WITH GRANT OPTION;"
mysql -h $rdsendpoint -u $user -p$rdspasswd -e "FLUSH PRIVILEGES;"
Note: This script makes use of AWS Secrets Manager (created at lab deployment) to pull the Amazon RDS database root user password and AWS Systems Manager Parameter Store (also created at lab deployment) to pull the Amazon RDS instance endpoint.
- On the Run a command page, in the Target selection section, configure the following values (leaving the rest with their default values):
For Target selection, select Choose instances manually.
For Instances, select the checkbox next to the
instance only.
- Scroll to the bottom of the page, and then choose Run.
The command takes approximately 20 seconds to complete.
- Wait a few seconds, and then use the refresh button to update the Overall status until it displays Success.
A banner message like the following is displayed at the top of the page: Command ID: 7fecac51-55ed-463d-a4fd-37b60fe44d1d was successfully sent!
This means that the Amazon EC2 instance database table and data have been migrated to the Amazon RDS instance.
Congratulations! In this task, you used Systems Manager Command documents, mysqldump software, and Parameter Store to migrate data from a standalone Amazon EC2 instance to an Amazon RDS for MariaDB database, which is deployed in a Multi-AZ configuration.
Task 6: Create a Launch Template
You can create a launch template that contains the configuration information to launch an instance. With launch templates, you can store launch parameters so that you do not need to specify them every time you launch an instance. In this step, you create a launch template to specify configuration parameters for launching instances with Amazon EC2 Auto Scaling groups (ASG).
As part of the lab, appropriate AWS Identity and Access Management (IAM) policies for the Amazon EC2 Auto Scaling group were provisioned.
Explore these IAM policies.
At the top of the AWS Management Console, in the search bar, search for and choose .
On the navigation menu at the left of the page, under Access management, choose Roles.
The browser displays the Roles page.
In the roles search box, input
.
Choose the wa-asg-instance-role link from the search results.
The browser displays the wa-asg-instance-role summary page.
- On the Summary page, you can access different details about the role. On the Permissions tab, notice the role has three attached policies:
(AWS managed policy).
(AWS managed policy).
(Inline policy).
With these policies, Systems Manager can communicate with the instances launched as part of the AWS Auto Scaling group. It can also run certain configuration commands on them.
Feel free to expand the policies by choosing the icon, and review the details of each policy.
Next, you create a security group for the launch template.
Return to the browser tab with the terminal. You might need to refresh the page if the terminal is timed out and unresponsive.
Create a security group for the launch template to use.
Command:
aws ec2 create-security-group --description "Launch Template Security group" --group-name "wa-asg-sg" --vpc-id $VPC --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"GroupId": "sg-0e96c2e6eb9ea98f7"
}
- Set the security group as an environment variable.
Command:
export asgSg=`aws ec2 describe-security-groups --filters Name=group-name,Values=wa-asg-sg --query 'SecurityGroups[*].GroupId' --output text --region $awsRegion` && echo asgSg=$asgSg >> ~/.bashrc
The command line returns to a new prompt when complete.
- Allow HTTP access through the Application Load Balancer security group.
Command:
aws ec2 authorize-security-group-ingress --group-id $asgSg --source-group $albSg --protocol "tcp" --port "80" --region $awsRegion
The command line returns to a new prompt when complete.
- Add the ASG security group as an ingress source to the Amazon RDS security group.
Command:
aws ec2 authorize-security-group-ingress --group-id $rdsSg --source-group $asgSg --protocol "tcp" --port "3306" --region $awsRegion
Next, create the launch template for the Amazon EC2 Auto Scaling group to use.
You use the existing web server instance as a starting point for the template.
- Find the Amazon Machine Image (AMI) used by the wa-web-server and set it as an environment variable.
Command:
export webAMI=`aws ec2 describe-instances --region $awsRegion --filters "Name=tag:Name,Values=wa-web-server" --query Reservations[].Instances[].ImageId[] --output=text` && echo webAMI=$webAMI >> ~/.bashrc
The command line returns to a new prompt when complete.
- Download a template for the user data, which instances launched by the Amazon EC2 Auto Scaling group will run when deploying.
Command:
cd ~
wget https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/userData-source.sh
Expected output: A sample of output returned to the terminal is as follows:
--2022-11-15 22:56:56-- https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/userData-source.json
Resolving aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)... 52.92.165.42, 52.92.212.146, 52.218.160.45, ...
Connecting to aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)|52.92.165.42|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1996 (1.9K) [application/json]
Saving to: ‘userData-source.json’
100%[=============================================================================================================================================>] 1,996 --.-K/s in 0s
2022-11-15 22:56:56 (63.8 MB/s) - ‘userData-source.json’ saved [1996/1996]
- Replace values in the user data template with the values of the environment variables you created and save it as a new file.
Command:
envsubst < userData-source.sh > userData.sh
The command line returns to a new prompt when complete.
Launch templates require that user data is base64 encoded to work with Amazon EC2.
- Encode the user data and save the value as an environment variable.
Command:
export userData=`base64 userData.sh | tr -d "\n"` && echo userData=$userData >> ~/.bashrc
The command line returns to a new prompt when complete.
- Download a template file of the launch template configuration to the shell instance.
Command:
cd ~
wget https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/waLaunchTemplate-source.json-v1.1.0
Expected output: A sample of output returned to the terminal is as follows:
--2022-11-15 22:56:56-- https://aws-tc-largeobjects.s3-us-west-2.amazonaws.com/ILT-TF-200-CSAWAF-10-EN/waLaunchTemplate-source.json-v1.1.0
Resolving aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)... 52.92.165.42, 52.92.212.146, 52.218.160.45, ...
Connecting to aws-tc-largeobjects.s3-us-west-2.amazonaws.com (aws-tc-largeobjects.s3-us-west-2.amazonaws.com)|52.92.165.42|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1996 (1.9K) [application/json]
Saving to: ‘waLaunchTemplate-source.json’
100%[=============================================================================================================================================>] 1,996 --.-K/s in 0s
2022-11-15 22:56:56 (63.8 MB/s) - ‘waLaunchTemplate-source.json’ saved [1996/1996]
- Replace the values in the launch template configuration file with the values of the environment variables you created and save it as a new file.
Command:
envsubst < "waLaunchTemplate-source.json-v1.1.0" > "waLaunchTemplate.json"
The command line returns to a new prompt when complete.
- Create a new launch template, referencing the new configuration file you created.
Command:
aws ec2 create-launch-template --launch-template-name "waLaunchTemplate" --launch-template-data file://waLaunchTemplate.json --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
{
"LaunchTemplate": {
"LatestVersionNumber": 1,
"LaunchTemplateId": "lt-081b3736684b2676b",
"LaunchTemplateName": "waLaunchTemplate",
"DefaultVersionNumber": 1,
"CreatedBy": "arn:aws:sts::046369250458:assumed-role/wa-lab-shell-role/i-0c880206f20302cc9",
"CreateTime": "2022-11-15T23:01:03.000Z"
}
}
- Set the newly created launch template as an environment variable.
Command:
export waLaunchTemplate=`aws ec2 describe-launch-templates --launch-template-names waLaunchTemplate --query 'LaunchTemplates[*].LaunchTemplateId' --output text --region $awsRegion` && echo waLaunchTemplate=$waLaunchTemplate >> ~/.bashrc
The command line returns to a new prompt when complete.
Congratulations! In this task, you created a launch template for the web app instances that is specific to the current AWS environment. This launch template is used by Amazon EC2 Auto Scaling to create a group of elastic web app instances.
Task 7: Create an Amazon EC2 Auto Scaling Group
An Amazon EC2 Auto Scaling group contains a collection of Amazon EC2 instances that are treated as a logical grouping for the purposes of automatic scaling and management. With Amazon EC2 Auto Scaling, you can take advantage of the safety and reliability of geographic redundancy by spanning Amazon EC2 Auto Scaling groups across multiple Availability Zones within a Region.
After performing the steps in this task, the architecture resembles the following diagram:
The architecture is an Amazon VPC containing 2 Availability Zones. There are 6 total subnets in the environment, with each Availability Zone having 3 of the subnets. The subnets are labelled and divided per Availability Zone as such: 1 public subnet, 1 private subnet, and 1 db private subnet. The public subnet in the first Availability Zone contains 2 Amazon EC2 instances; one is labelled web app instance and the other is labelled shell server instances. Each of the private subnets is part of an Amazon EC2 Auto Scaling group and contains 1 web server each. Each of the db private subnets contain 1 Amazon RDS instance each. Internet traffic flows into an internet gateway, to an Application Load Balancer, then to the Amazon EC2 Auto Scaling group in the private subnets, and finally to the Amazon RDS primary instance in the db private subnet.
In this task, you create an Amazon EC2 Auto Scaling group.
- Set the first subnet included in the Amazon EC2 Auto Scaling group as an environment variable.
Command:
export asgSubnet1Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-private-subnet-1 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo asgSubnet1Id=$asgSubnet1Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Set the second subnet included in the Amazon EC2 Auto Scaling group as an environment variable.
Command:
export asgSubnet2Id=`aws ec2 describe-subnets --filters Name=tag:Name,Values=wa-private-subnet-2 --query 'Subnets[*].SubnetId' --output text --region $awsRegion` && echo asgSubnet2Id=$asgSubnet2Id >> ~/.bashrc
The command line returns to a new prompt when complete.
- Create the Amazon EC2 Auto Scaling group, referencing the launch template created previously.
Command:
aws autoscaling create-auto-scaling-group --auto-scaling-group-name "waAutoscaleGroup" --launch-template LaunchTemplateId=$waLaunchTemplate --min-size "2" --max-size "4" --target-group-arns $waTg --vpc-zone-identifier "$asgSubnet1Id,$asgSubnet2Id" --region $awsRegion
The command line returns to a new prompt when complete.
This process might take 2-3 minutes to complete. Wait that amount of time before proceeding to the next step.
At the top of the AWS Management Console, in the search bar, search for and choose .
On the navigation menu at the left of the page, under Instances, choose Instances.
The browser displays the Instances page.
New instances are displayed on the dashboard as they are created. Their name should read as wa-auto-scale-group. Make sure to refresh the page for updated instance information.
Note: After a few minutes, both of the Amazon EC2 instances in the wa-auto-scale-group have an instance state shown as Running and with a Status check 2/2 checks passed, which means your Amazon EC2 Auto Scaling group is successfully set up.
- On the navigation menu at the left of the page, under Load Balancing, choose Load Balancers.
An Application Load Balancer named
is displayed in the list.
- Choose the waAlb Application Load Balancer.
The browser displays the waAlb details page.
From the Description section, copy the DNS name value.
Paste the Application Load Balancer DNS name in a new web browser tab.
The web application is displayed.
Caution: The application takes a couple of minutes to fully deploy. Before the deployment finishes, you might receive a “502 Bad Gateway” error. This is because the instances are still bootstrapping and the Application Load Balancer has not registered the new instances.
- After the application is displayed, insert a couple of new items into the table to validate the application is working correctly.
Congratulations! In this task, you created an Amazon EC2 Auto Scaling group for the application instances using a template file and resource values from your AWS environment. You then validated the Amazon EC2 Auto Scaling group was reachable from the Application Load Balancer DNS.
Task 8: Create Route 53 Health Checks
Amazon Route 53 health checks monitor the health and performance of your web applications, web servers, and other resources. Each health check you create can monitor one of the following:
The health of a specified resource, such as a web server.
The status of other health checks.
The status of an Amazon CloudWatch alarm.
In this task, you configure a health check to monitor the Amazon EC2 failure injection that you test in the last activity of this lab.
- At the top of the AWS Management Console, in the search bar, search for and choose .
Note: If an error message like “Route 53 couldn’t update the page” is displayed at the top of the page, then this error can be safely ignored for this lab. Continue with the following steps.
On the navigation menu at the left of the page, choose Health checks.
Choose Create health check.
The browser displays the Create health check page.
- On the Create health check page, in the Configure health check section:
For Name, input
.
For What to monitor, choose Endpoint.
- On the Create health check page, in the Monitor an endpoint section:
For Specify endpoint by, choose Domain name.
For Protocol, select HTTP.
For Domain name, paste the ELB DNS name.
For Path, input
.
Caution: The ELB DNS name you copied earlier from the load balancers page. Do not include the
protocol if you copied the value from your browser address bar.
Expand the Advanced configuration section.
On the Create health check page, in the Advanced configuration section:
For Request interval, select Fast (10 seconds).
For Failure threshold, input
.
- Choose Next.
The browser displays the Get notified when health check fails page.
For Create alarm, select No.
Choose Create health check.
Note: You might get this error message, “Error creating health check. Invalid fully qualified domain name: It may not contain reserved characters of RFC1738 “;/?:@=&”.” If so, confirm the Domain name does not include “http://”. The best option here is to copy the DNS name in the Application Load Balancer information from the Amazon EC2 console.
A banner message like the following is displayed at the top of the page: Health check with id 7326c3b0-df98-4b20-aeba-590a9c7e8d49 has been created successfully.
- Refresh the table on your screen until the health check status shows Healthy.
Next, review the application health status.
Select the
health check you just created.
In the panel below, select the Monitoring tab.
After a couple of minutes, the application health check status updates with data points. In the Health check status graph,
indicates the application isUP, andindicates the application isDOWN.
The AWS Route 53 dashboard is shown with one health check present.
Congratulations! In this task, you setup an Amazon Route 53 health check, to monitor the deployed service for any downtime.
Task 9: Validate Amazon EC2 Auto Scaling Resiliency Against Failure
Failure injection, also known as chaos testing, is an effective and essential method to validate and understand the resiliency of your workload and is a recommended practice of the AWS Well-Architected Reliability pillar.
Learn more about using chaos engineering to test resiliency in the AWS Documentation.
In this task, you initiate one failure scenario and assess how your system reacts.
PREPARE TO TEST
- Open a web browser to the ELB DNS name to monitor application connectivity:
The app contains entry fields labelled as: Category, description and price. There is a button labelled update database. And there is a data table at the bottom of the page. The data table contains 5 examples.
At the top of the AWS Management Console, in the search bar, search for and choose .
On the navigation menu at the left of the page, under Instances, choose Instances.
There are two Amazon EC2 instances running that have a name beginning with
. For these Amazon EC2 instances note the following:
Each has a unique Instance ID.
There is one instance per Availability Zone.
Both instances are healthy.
The Amazon EC2 console is shown the instances page. In the list, two Amazon EC2 instances named wa-auto-scale-group are highlighted.
Open the AWS Management Console in two additional browser tabs. On the navigation menu at the left of the page, open Target Groups and Auto Scaling Groups in separate tabs.
In the first new tab, on the navigation menu at the left of the page, under Load Balancing, choose Target groups.
In the second new tab, on the navigation menu at the left of the page, under the Auto Scaling section, choose Auto Scaling Groups.
Leave these two tabs open. You now have three consoles open.
AMAZON EC2 FAILURE INJECTION
- Go back to the EC2 Instance Connect terminal, and run the following command to get instances in the Amazon EC2 Auto Scaling group.
Command:
aws ec2 describe-instances --filters Name=tag:Name,Values=wa-auto-scale-group --query 'Reservations[].Instances[*].{InstanceID:InstanceId,Type:InstanceType,AZ:Placement.AvailabilityZone,PrivateIP:PrivateIpAddress,Subnet:SubnetId,Time:LaunchTime,State:State.Name}' --output table --region $awsRegion
Expected output: A sample of output returned to the terminal is as follows:
--------------------------------------------------------------------------------------------------------------------------------------
| DescribeInstances |
+------------+----------------------+---------------+----------+---------------------------+----------------------------+------------+
| AZ | InstanceID | PrivateIP | State | Subnet | Time | Type |
+------------+----------------------+---------------+----------+---------------------------+----------------------------+------------+
| us-east-1b| i-0150ec4ddf89b8423 | 10.100.3.184 | running | subnet-0304726ddc54413f4 | 2022-11-18T21:28:08.000Z | t3.micro |
| us-east-1a| i-0582f19f8abf13bdf | 10.100.1.67 | running | subnet-0d75e3d100670c7b9 | 2022-11-18T21:28:09.000Z | t3.micro |
+------------+----------------------+---------------+----------+---------------------------+----------------------------+------------+
Choose one of the Instance IDs from the table.
Replace YOUR_INSTANCE_ID in the following command, with your chosen InstanceID from the table. This command will terminate the instance that you choose. This will simulate a critical problem with one of the two web servers used by your service.
Command:
aws ec2 terminate-instances --region $awsRegion --instance-ids YOUR_INSTANCE_ID
Expected output: A sample of output returned to the terminal is as follows:
{
"TerminatingInstances": [
{
"InstanceId": "i-0150ec4ddf89b8423",
"CurrentState": {
"Code": 32,
"Name": "shutting-down"
},
"PreviousState": {
"Code": 16,
"Name": "running"
}
}
]
}
- Go to the web browser with the application that you already have open. The application should continue to respond normally.
The app contains entry fields labelled as: Category, description and price. There is a button labelled update database. And there is a data table at the bottom of the page. The data table contains 5 examples.
At the top of the AWS Management Console, in the search bar, search for and choose
.
On the navigation menu at the left of the page, under Instances, choose Instances.
Examine the two Amazon EC2 instances. Make sure the filter Instance state:Running is removed. After running the terminate command, the chosen instance changes its state to shutting-down and then Terminated.
Refresh the page to receive the updated instance information.
The Amazon EC2 console is shown the instances page. In the list, one Amazon EC2 instance named wa-auto-scale-group are highlighted. It’s instance state is shutting-down.
- Go to the Target Groups console you already have open in one of your browser tabs. Choose , and then select the Targets tab:
The Application Load Balancer only sends traffic to healthy instances. There is only one target with a status of healthy. There might be two healthy instances if you wait too long because the Amazon EC2 Auto Scaling group will successfully register the new instance as a target. To update the Registered targets table, use the console refresh button .
When the Amazon EC2 Auto Scaling group launches a new instance, it is automatically added to the Application Load Balancer target group.
The unhealthy instance is the newly added one. The Application Load Balancer does not send traffic to it until it the instance has completed initializing. The instance ultimately transitions to healthy and then starts receiving traffic.
The new instance was launched in the same Availability Zone as the terminated one. Amazon EC2 Auto Scaling automatically maintains balance across all the Availability Zones you specified.
Go to the Auto Scaling Groups console you already have open, and select the waAutoscaleGroup Amazon EC2 Auto Scaling group in the table.
Choose the Activity tab, and observe the following in the Activity history section:
First, an instance was taken out of service in response to an Amazon EC2 health check indicating it was terminated or stopped.
Next, an instance was started in response to a difference between the desired and the actual capacity, increasing the capacity from 1 to 2.
Next, monitor the health in Amazon Route 53.
At the top of the AWS Management Console, in the search bar, search for and choose
.
On the navigation menu at the left of the page, choose Health checks.
Choose the health check named
.
Select the Monitoring tab. No application downtime was observed during the test.
Congratulations! In this task, you tested and observed the failure resiliency of your architecture by purposefully terminating one of the instances in the Amazon EC2 Auto Scaling group.
Lab Complete
Congratulations! You completed the lab.
Deploying multiple servers and Elastic Load Balancing allows a service to recover after the loss of an instance without availability disruptions. Traffic from users is automatically routed to healthy instances. Amazon EC2 Auto Scaling ensures that unhealthy hosts are removed and replaced with healthy ones to maintain high availability.
Availability Zones are isolated sets of resources within a Region, each with redundant power, networking, and connectivity, housed in separate facilities. Each Availability Zone is isolated, but the Availability Zones in an AWS Region are connected through low-latency links. AWS provides you with the flexibility to place instances and store data across multiple Availability Zones within each AWS Region for high resiliency.
In this lab, you learned how to:
Expand an existing architecture to a second Availability Zone.
Add subnets to an Availability Zone.
Deploy Amazon RDS using a multiple Availability Zones configuration.
Update Parameter Store, a capability of AWS Systems Manager, for database credentials.
Create an Application Load Balancer and a target group.
Migrate a database from a standalone instance to Amazon RDS using the Systems Manager Run Command.
Create a launch template.
Create an Amazon EC2 Auto Scaling group.
Create Amazon Route 53 health checks.
Test your application reliability by terminating instances from the AWS Auto Scaling group.
End lab
Follow these steps to close the console and end your lab.
Return to the AWS Management Console.
At the upper-right corner of the page, choose AWSLabsUser, and then choose Sign out.
Choose End lab and then confirm that you want to end your lab.
For more information about AWS Training and Certification, see aws.amazon.com/training.
Your feedback is welcome and appreciated.
If you would like to share any feedback, suggestions, or corrections, please provide the details in our