Git Hub Actions Deployment to Azure Static Website

I invite you to read my solution to the A Cloud Guru Azure Resume Challenge . I embarked on this latest challenge in in order to learn and practice Azure and also, to add to my Cloud Architect Portfolio.

Azure Resume Challenge

This is the diagram A Cloud Guru included to visualize the challenge:

resume-challenge.png

and here is the solution that I implemented in response to this challenge:

github-actions-cicd-project.png

Goal

The objective of this project was to create a static web site in Azure Blob storage with the following features:

  • HTTPS
  • Content Delivery Network (CDN)
  • Azure Function integrated with Cosmos DB to count website loads
  • Git Hub Actions to automate the deployment of website code (html, javascript, css, images, etc)

The objective was achieved by designing and building a solution using Blob Storage, CDN, Custom Domain, Function, Cosmos DB services from Azure and Git Hub Actions.

Outcome

In completing this project I was able to gain real-world skills in Git Hub Actions, Blob Storage Static Website, Cosmos DB and Functions.

Main Steps

This project was completed in five steps:

Step 1. Created 8 Azure CLI commands that create the necessary Azure infrastructure

## Azure CLI Resource Group Creation
> az group create --name StaticWebsiteRG --location canadacentral

## Azure CLI Storage Account Creation
> az storage account create --name briangithubactions --resource-group StaticWebsiteRG --location canadacentral --sku Standard_LRS

## Azure CLI Blob Static Website Creation
> az storage blob service-properties update --account-name briangithubactions --static-website --404-document 404.html --index-document index.html

## Azure CLI Create a Content Delivery Network (CDN) profile
> az cdn profile create --resource-group StaticWebsiteRG --name MyCDNProfile --sku Standard_Microsoft

## Azure CLI Create a Content Delivery Network (CDN) endpoint
> az cdn endpoint create --resource-group StaticWebsiteRG --name brian-gaber --profile-name MyCDNProfile --origin briangithubactions.z9.web.core.windows.net --origin-host-header briangithubactions.z9.web.core.windows.net

## Azure CLI Create URL Redirect rule to redirect any HTTP requests to HTTPS
> az cdn endpoint rule add --resource-group StaticWebsiteRG --name brian-gaber --profile-name MyCDNProfile --order 1 --rule-name "redirect" --match-variable RequestScheme --operator Equal --match-values HTTP --action-name "UrlRedirect" --redirect-protocol Https --redirect-type Moved

### Before you can use a custom domain with an Azure CDN endpoint, you must first create a canonical name (CNAME) record with Azure DNS or your DNS provider to point to your CDN endpoint.
### https://docs.microsoft.com/en-us/azure/cdn/cdn-map-content-to-custom-domain

## Azure CLI Create a custom domain for your endpoint
> az cdn custom-domain create --resource-group StaticWebsiteRG --endpoint-name brian-gaber --profile-name MyCDNProfile --name MyCustomDomain --hostname briangaber.esnap.ca

## Azure CLI Enable https
az cdn custom-domain enable-https --resource-group StaticWebsiteRG --endpoint-name brian-gaber --profile-name MyCDNProfile --name MyCustomDomain

Step 2. Created a Git Hub Actions main.yml to deploy the website code upon a push of the code to my Git Hub repository.

name: Blob storage website CI

on:
    push:
        branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:            
    - uses: actions/checkout@v2
    - uses: azure/login@v1
      with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Upload to blob storage
      uses: azure/CLI@v1
      with:
        azcliversion: 2.23.0
        inlineScript: |
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.html
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.css
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.js
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.png
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.jpg
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.gif
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.xml
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.thmx
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.eot
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.svg
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.ttf
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.woff
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.less
            az storage blob upload-batch --account-name briangithubactions -d '$web' -s . --pattern *.scss
    - name: Purge CDN endpoint
      uses: azure/CLI@v1
      with:
        azcliversion: 2.23.0
        inlineScript: |
           az cdn endpoint purge --content-paths  "/*" --profile-name MyCDNProfile --name "brian-gaber" --resource-group StaticWebsiteRG

  # Azure logout 
    - name: logout
      run: |
            az logout

Step 3. Created a canonical name (CNAME) record with my DNS provider to point to my CDN endpoint. In my case I use AWS Route 53 as my DNS provider.

Step 4. A simple static website was created and GitHub was used for source control.

Step 5. Created one Azure Function to integrate the static website with Cosmos DB.

function-integration.png

Solution

The final solution is composed of these Azure Services:

Azure Services UsedPurpose
Resource GroupContainer for all Azure Services
Storage AccountBLOB Storage Static Website Container to store all website objects
CDNContent Deliver Network to enable worldwide low latency
CosmosDBNoSQL Database that contains the JSON formatted User Documents
Function AppFunctions to read and update the website load counter from Cosmos DB
Git Hub ActionsCICD of the Static Web Site code

New Knowledge Acquired

I took two A Cloud Guru courses (Deployment Pipelines using GitHub Actions and Serverless Computing with Azure Functions) to prepare myself to complete this project.

Solution Artifacts

The Git Hub repository for this project is found at: Azure Git Hub Actions Project

Rewards and Lessons Learned

The hardest part of this challenge was creating one function that performed both the read and update of Cosmos DB. Initially, I thought I would require two Azure Functions: one to read the counter value and a second to update the counter value. I find it elegant that, with one Function triggered by a HTTP request, I can read a value from CosmosDB, change that value in my Function and then update CosmosDB with the new value. Learning and implementing Git Hub Actions was the part of this project I enjoyed the most because, for whatever reason, I find CICD a very interesting technology. The biggest takeaways were learning Git Hub Actions and enhancing both my DevOps and Azure function skills.

Azure Function CORS - The Azure Function that integrates with CosmosDB has a different origin than the CDN endpoint and CNAME record. Therefore, a CORS permission was required for the Function.

Azure Python Functions - since my Azure Function is written in Python then it needed to be deployed using VS Code with the Azure Functions extension.

Test Drive

You can find my creation at Brian's Online Resume. Make sure to pay close attention to the "View" counter. :)

The website may not function because cloud having a pay as you go fee structure means I will incur costs if I leave the solution up indefinitely. Therefore, with the goal of cost avoidance I will have shutdown most of the cloud resources associated with this project sometime in June 2021.

Conclusions

This is the fifth A Cloud Guru challenge I have completed and I have learned extensively through completing these challenges. Without a doubt, the highlight of this challenge has been learning Git Hub Actions. It has been a very valuable experience and I encourage anyone who wants to improve their Cloud Architect skills to complete these challenges.