Level-1 Architecture

As I mentioned in Part 1 - Introduction, this blog series develops a series of deployment architectures to mirror the recommendations made in the Scaling Up to Your First 10 million Users

The original video just describes a series a recommendations; I demarcated the recommendations into a few “levels”. “Level” is the word that I am using for the purpose of this blog series.

Create Security Group and Allow Incoming Traffic

Create security group:

aws ec2 create-security-group --group-name "my-sg-level1" \
    --description "Security group, level1"

Allow incoming traffic on ports 22, 80 and 443 for ssh, http and https.

aws ec2 authorize-security-group-ingress --group-name my-sg-step1 \
    --protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-name my-sg-step1 \
    --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-name my-sg-step1 \
    --protocol tcp --port 443 --cidr 0.0.0.0/0

Create Key Pair

Create key pair and save the certificate file:

aws ec2 create-key-pair --key-name UsEast1KP --query 'KeyMaterial' \
    --output text > acct93user1.pem

Obtain Image ID

Obtain image id for the latest Amazon Linux 2 image:

aws ec2 describe-images --filters "Name=name,Values=amzn2-ami-hvm-2.0*-x86_64-gp2" | jq -r '.Images[].Name' | sort | tail -1 > image_name.txt

IMAGE_NAME=`cat image_name.txt`
aws ec2 describe-images --filters "Name=name,Values=$IMAGE_NAME" | jq -r '.Images[].ImageId' > image_id.txt

Launch an Instance, obtain public IP address & instance ID

Launch an EC2 instance:

IMAGE_ID=`cat image_id.txt`
SG_ID=`cat sg_id.txt`
aws ec2 run-instances --image-id $IMAGE_ID --instance-type t2.micro --key-name UsEast1KP --security-group-ids $SG_ID

Install Required Software and Application to EC2 Instance

Follow the instructions in Part 3b to install the required software and application to the EC2 instance. After completing the steps in Part 3b, come back here and continue with allocating Elatic IP address.

Allocate and Associate Elastic IP Address

aws ec2 allocate-address

aws ec2 describe-addresses --query "Addresses[0].PublicIp" | sed 's/"//g' > elastic_ip_addr.txt

ELASTIC_IP_ADDR=`cat elastic_ip_addr.txt`
aws ec2 associate-address --instance-id `cat instance_id.txt` --public-ip $ELASTIC_IP_ADDR

Register Domain

Register a domain with a registrar of your choice. I registered my domain with GoDaddy. You can also register a domain using Route53.

The instructions outlined in the following sections are for the scenario when you register your domain using an outside registrar. Some of the steps are different in the case where the domain is registered using Route53.

Save the domain name in a text file domain_name.txt.

Create Hosted Zone

CALLER_REF=$(date +%Y-%m-%d-%H:%M:%S)
DOMAIN_NAME=`cat domain_name.txt`
RETURN_JSON=$(aws route53 create-hosted-zone --name $DOMAIN_NAME --caller-reference $CALLER_REF)
echo $RETURN_JSON | jq '.HostedZone.Id' | sed 's/"//g' | sed 's#/hostedzone/##' > hosted_zone_id.txt
echo $RETURN_JSON | jq '.ChangeInfo.Id' | sed 's/"//g' | sed 's#/change/##' > create_hz_change_id.txt

We create a hosted zone using the domain as the hosted zone’s name. Hosted zone creation also needs a caller reference parameter which is required to be unique. We use a timestamp as caller reference.

We also need to save two pieces of information from the json returned by the create hosted zone request: Hosted Zone Id and Change Id.

Hosted zone creation is treated as a request by Route53. For this reason, we need to save the Change ID information returned by the create-hosted-zone request. We can then use the change id to query the status:

CHANGE_ID=`cat create_hz_change_id.txt`
aws route53 get-change --id $CHANGE_ID --query "ChangeInfo.Status"

Requests to Route53 are assigned an initial status of PENDING. Upon completion of the request, the status changes to INSYNC. Before moving on to the record set creation step, we have to make sure the hosted zone creation request has the INSYNC status.

Create Record Sets

DOMAIN_NAME=`cat domain_name.txt`
aws route53 change-resource-record-sets --hosted-zone-id `cat hosted_zone_id.txt` \
    --change-batch '{
        "Changes": [
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "'$DOMAIN_NAME'",
                    "Type": "A",
                    "TTL": 60,
                    "ResourceRecords": [ { "Value": "'$(cat elastic_ip_addr.txt)'"} ]
                    }
            },
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "www.'$DOMAIN_NAME'",
                    "Type": "A",
                    "AliasTarget": {
                        "HostedZoneId": "'$(cat hosted_zone_id.txt)'",
                        "DNSName": "'$DOMAIN_NAME'",
                        "EvaluateTargetHealth": false
                    }
                }
            },
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "*.'$DOMAIN_NAME'",
                    "Type": "A",
                    "AliasTarget": {
                        "HostedZoneId": "'$(cat hosted_zone_id.txt)'",
                        "DNSName": "'$DOMAIN_NAME'", "EvaluateTargetHealth": false
                    }
                }
            }
        ]
    }' > /tmp/record_sets_create_info.txt

cat /tmp/record_sets_create_info.txt | jq '.ChangeInfo.Id' | sed 's/"//g' | sed 's#/change/##' > create_rs_change_id.txt

Verify that record set creation request has its status set to INSYNC:

CHANGE_ID=`cat create_rs_change_id.txt`
aws route53 get-change --id $CHANGE_ID --query "ChangeInfo.Status"

Get Delegation Set and Update Nameserver Records with Domain Registrar

HOSTED_ZONE_ID=`cat hosted_zone_id.txt`
aws route53 get-hosted-zone --id $HOSTED_ZONE_ID --query "DelegationSet" > delegation_set.txt

The delegation set is a list of name servers that looks similar to the list shown below:

{
    "NameServers": [
        "ns-xxx.awsdns-xx.net",
        "ns-xxx.awsdns-xx.com",
        "ns-xxxx.awsdns-xx.co.uk",
        "ns-xxxx.awsdns-xx.org"
    ]
}

We need to update our domain’s name servers on the domain registrar’s site.