AWS Cloud Resume Challenge

AWS Cloud Resume Challenge

Serverless Website deployment using Infrastructure as Code

·

3 min read

What is this challenge?

The Cloud Resume Challenge is a multiple-step resume project which helps build and demonstrate skills fundamental to pursuing a career as an AWS Cloud Engineer. The project was published by Forrest Brazeal. Details of this challenge can be found here. The final result can be seen here.

Big picture of deployments

This project is about creating a website which is hosted on amazon S3, then on the site display the number of visitors which is calculated with an AWS Lambda Function and stored in DynamoDB table.

image.png

The tasks and the progression

  1. HTML
    The CV is needed to be a HTML document which is styled using CSS. It doesn't need to be an original masterpiece, any HTML CV template will be acceptable. You can find mine here for inspiration.

  2. CSS
    The same goes to CSS too. You can write your own, or use tailwind or something similar.

  3. Static Website
    The HTML/CSS website should be deployed to an AWS S3 bucket. I have done it via CloudFormation template. The code is below:

    MyWebsite:
     Type: AWS::S3::Bucket
     Properties:
       AccessControl: PublicRead
       WebsiteConfiguration:
         IndexDocument: index.html
       BucketName: cloud-cv-website
    
  4. Javascript
    The CV webpage should include a visitor counter that displays how many people have accessed the site. This script should be written in JavaScript. For the counter to work, we need to add a few extra line in our HTML website and write a JavaScript code:

    var dev_env = false
             if (dev_env == false) {
                 fetch("https://8tqg9v6zog.execute-api.us-east-1.amazonaws.com/prod/hello")
                     .then(function (response) {
                         return response.json()
                     })  
                     .then(function (myJson) {
                         console.log("Visitor Count: " + myJson.visit_count);
                         document.querySelector("#visitorCount").innerHTML = "Total visitors: " + myJson.visit_count;
                     })
                     .catch(function (error) {
                         console.log("Error: " + error)
                     })
             }
    

    The HTML addition:

    <p class="h3 email"><span id="visitorCount"></span></p>
    
  5. Database
    The visitor counter will need to retrieve and update its count in a database somewhere. I have used DynamoDB for this task as it was the most convenient solution. The code from the CloudFormation template to create the DynamoDB table:

    DynamoDBTable:
     Type: AWS::DynamoDB::Table
     Properties:
       TableName: cloud_resume
       BillingMode: PAY_PER_REQUEST
       AttributeDefinitions:
         - AttributeName: "ID"
           AttributeType: "S"
       KeySchema:
         - AttributeName: "ID"
           KeyType: "HASH"
    
  6. API
    We shouldn't communicate directly with DynamoDB from our Javascript code. Instead, a REST API should be created that accepts requests from your web app and communicates with the database.

  7. Python
    The Lambda script to retrieve the counter from the database and update the number should be written in Python. The final script is below:

import json
import boto3
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('cloud_resume')

def lambda_handler(event, context):
    response = table.get_item(
        Key = {
            'ID':'visit'
        }
    )

    visit_count = response['Item']['counts'] 
    visit_count = int(visit_count) + 1

    response = table.put_item(
        Item = {
            'ID':'visit',
            'counts': visit_count
        }
    )
    # print(visit_count)

    responseBody = json.dumps({"visitorCount": visit_count})
    logger.debug("Execution complete")
    # return {
    #    'statusCode': 200,
    #    'body':  f'{visit_count}'
    #}

    apiResponse = {
        "isBase64Encoded": False,
        "statusCode": 200,
        #"visitorCount": int(float(ddbResponse["Attributes"]["amount"])),
        "body": responseBody,
        "headers": {
            "Access-Control-Allow-Headers" : "Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "GET,OPTIONS" 
        },
    }
    return {"visit_count": visit_count}

And to deploy it via CloudFormation:

Lambdafunction:
    Type: AWS::Serverless::Function
    Properties:
      Policies:
        - DynamoDBCrudPolicy:
            TableName: cloud_resume
      CodeUri: Lambda/
      Handler: visitor_count.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Events:
        getCount:
          Type: Api
          Properties:
            Path: /
            Method: get

8.Infrastructure as Code
I have used the AWS Serverless Application Model (SAM) template and deployed the different services using the AWS SAM CLI. The code snippets can be found under each step where applicable.

9.Blog post
The final step is to write a blog about the experience and what I have learned during the project work. You are reading this blog right now.