Skip to main content

Command Palette

Search for a command to run...

#CloudGuruChallenge: Your resume in Azure

Updated
6 min read
#CloudGuruChallenge: Your resume in Azure

Azure Cloud Resume Challenge

https://acloudguru.com/blog/engineering/cloudguruchallenge-your-resume-in-azure

The final output
https://www.resume.elston.co.in/

GitHub Link : https://github.com/ElstonMisquitta88/cloudguru-azure-resume

The main purpose of taking the challenge was that I am new to Azure and wanted to learn more and work on Azure services. This became quite a learning experience. Trying out the servies and deploying on a live environment was fun.

I have divided the work done into the following steps:

  1. Create a Static Website.
  2. Custom Domain for the Website.
  3. Workflow in Github for the static website.
  4. Create a Cosmos DB for saving the website visitor count.
  5. Create a Function to Fetch/Update the visitor count.
  6. Create a KeyValult to save the Cosmos DB connection string.
  7. Workflow in Github for the Function.
  8. Create a simple Unit test for the Function

(Step 1) Create a Static Website

  • Create a Repository in GitHub. 01_GitHub.png

  • Used a website template from https://templateflip.com/

  • Added the files to the GitHub Repository.

  • Installed GitHub Desktop to create a local clone copy.

  • In Visual Studio via the Source Control Option - Push any changes in the files to GitHub Repository.

02_VisualStudioCode.png

  • Create a Resource Group on Azure Portal Via CLI

Prior to this step you need to install Azure CLI or use Via Cloud Shell in Azure Portal

03_CloudShel.png In CMD type (this is to login into azure)

az login

You will be redirected to a web page for Azure subscription authentication.

az group create --location   --name
az group create -l westindia -n rg_cg_resume
  • Next step is to create a Storage Account
az storage account create --name --resource-group
az storage account create --name cgresume --resource-group rg_cg_resume --kind StorageV2 --access-tier hot --location westindia --sku Standard_LRS
  • In Azure portal navigate to the storage account which you have just created. In that search for Static Website option is the left hand side blade.

04.png

Enable the static Website and add the name of the default page to be used. Click on Save.

05.png

After saving the Primary endpoint will be generated. You can use this link to view your website.

(Step 2) Custom Domain for the Website

  • To assign a custom Domain we will need to create first a CDN profile.

06_CDN.png

  • After creating the CDN Profile you will need to create a Endpoint which will point to the storage account holding the static website.

07_CDN_Endpoint.png

  • Give a name for the endpoint.

  • Origin Type - Storage static website

  • Origin Hostname - Enter the Primary endpoint which was generated from the storage static website(This will be available to select from the dropdown)

  • After creation of the endpoint, after sometime you will be able to view your website via the Endpoint hostname. (This will take some time)

  • Now we will need to assign your custom domain to the endpoint created.

  • First create a CNAME record will your domain provider pointing to the Endpoint hostname.

  • After that create a custom domain entry and save.

08_CustomDomain.png

  • Next Step is to enable HTTPS for the domain.

09_Https_enable.png

At this point we have our basic website up and running with Https enabled.

(Step 3) Workflow in Github for the static website

  • We will create a Workflow in GitHub to publish any changes checked in GitHub.

    https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-static-site-github-actions

  • You need to execute this is Azure CLI

az ad sp create-for-rbac --name {myStaticSite} --role contributor --scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group} --sdk-auth
  • Replace the placeholders with your subscription ID and resource group name. The output is a JSON object with the role assignment credentials that provide access to your storage account similar to below. Copy this JSON object for later.
{
    "clientId": "<GUID>",
    "clientSecret": "<GUID>",
    "subscriptionId": "<GUID>",
    "tenantId": "<GUID>",
    (...)
  }
  • Configure the GitHub secret

  • In GitHub, browse your repository.

  • Select Settings > Secrets > New secret.

  • Paste the entire JSON output from the Azure CLI command into the secret's value field. Give the secret a name like AZURE_CREDENTIALS.

  • Go to Actions for your GitHub repository.

  • Select Set up your workflow yourself.

  • The file will appear in the .github/workflows folder of your repository

name: Blob storage website CI

on:
    push:
        branches: [ main]
    pull_request:
        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.0.72
        inlineScript: |
            az storage blob upload-batch --account-name <STORAGE_ACCOUNT_NAME> -d '$web' -s .
    - name: Purge CDN endpoint
      uses: azure/CLI@v1
      with:
        azcliversion: 2.0.72
        inlineScript: |
           az cdn endpoint purge --content-paths  "/*" --profile-name "CDN_PROFILE_NAME" --name "CDN_ENDPOINT" --resource-group "RESOURCE_GROUP"

  # Azure logout 
    - name: logout
      run: |
            az logout
  • Review your deployment
  • Go to Actions for your GitHub repository.
  • Open the first result to see detailed logs of your workflow's run.

(Step 4) Create a Cosmos DB for saving the website visitor count.

cosmos.png

(Step 5) Create a Function to Fetch/Update the visitor count

  • Create a HTTP Trigger Function via Visual Studio Code. In that we will be using Input / Output binding to fetch and update value from Cosmos DB.
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net;
using System.Net.Http;
using System.Text;

namespace CustomCounter
{
     public class Counter
    {
        [JsonProperty(PropertyName = "id")]
        public string Id {get; set;}

        [JsonProperty(PropertyName = "index")]
        public string index {get; set;}


        [JsonProperty(PropertyName = "Count")]
        public int Count {get;set;}

    }
    public static class ResumeCounterTrigger
    {
        [FunctionName("GetResumeCounter")]
        public static HttpResponseMessage Run(
            [HttpTrigger(AuthorizationLevel.Anonymous , "get", Route = null)] HttpRequest req,
                     [CosmosDB(
                    databaseName:"CloudResume", 
                    collectionName: "tblCloudResume",
                    ConnectionStringSetting = "democosmos_DOCUMENTDB", 
                    Id = "One", 
                    PartitionKey = "RecordCount")] Counter Readcounter,  
                    [CosmosDB(
                        databaseName:"CloudResume",
                        collectionName: "tblCloudResume",
                        ConnectionStringSetting = "democosmos_DOCUMENTDB",
                        Id = "One", 
                        PartitionKey = "RecordCount")] out Counter updatedCounter,            
            ILogger log)
        {
                log.LogInformation("GetResumeCounter was triggered.");
                updatedCounter = Readcounter;
                updatedCounter.Count += 1;
           var jsonToReturn = JsonConvert.SerializeObject(updatedCounter);
           return new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(jsonToReturn, Encoding.UTF8, "application/json")
            };
        }
    }
}
  • Next a create a function App in the Azure Portal. Have selected consumption based function.
  • Have enabled Application Insights for the same.
  • You also have to enable CORS (use the URL of the static website) to use the function.

(Step 6) Create a KeyValult to save the Cosmos DB connection string

  • In order to prevent the Cosmos DB connection string in the function to be plain text we will be using KeyValult by creating a secret.

https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal

Additional steps to be done

  • Enable Managed Identify in Azure Functions https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview

01_Function_Identity.png

  • In Key vault add access policy for the created Identity

02+keyvalult.png

  • Finally in the function, in Application Settings add the value for the Cosmos DB connection string.

https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references

03_Functions.png

(Step 7) Workflow in Github for the Function.

  • We will create a workflow for publishing Function code to the Function app.
name: WebSiteFunctions

# Deploy push made from Functions folder.
on:
  push:
        branches: [ main ]
        paths:
        - 'Functions/**'


# CONFIGURATION
# For help, go to https://github.com/Azure/Actions
# 1. Paste the RBAC json into the following secret in your repository:
#   AZURE_RBAC_CREDENTIALS
# 2. Change these variables for your configuration:

env:
  AZURE_FUNCTIONAPP_NAME: <Function App Name>  
  AZURE_FUNCTIONAPP_PACKAGE_PATH: '<path to your web app project, defaults to the repository root>'  
  DOTNET_VERSION: '3.1'    # dotnet version

jobs:
  build-and-deploy:
    runs-on: windows-latest
    steps:
    - name: 'Checkout GitHub Action'
      uses: actions/checkout@master

    - name: 'Login via Azure CLI'
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Setup DotNet ${{ env.DOTNET_VERSION }} Environment
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.DOTNET_VERSION }}

  - name: 'Run dotnet'
      shell: pwsh
      run: |
        pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/API'
        dotnet build --configuration Release --output ./output
        popd

    - name: 'Run Unit Test'
      shell: pwsh
      run: | 
        pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/Test'
        dotnet test

    - name: 'Run Azure Functions Action'
      uses: Azure/functions-action@v1
      id: fa
      with:
        app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
        package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/API/output'

(Step 8) Create a simple Unit test for the Function

https://madebygps.com/how-to-use-xunit-with-azure-functions/

https://docs.microsoft.com/en-us/azure/azure-functions/functions-test-a-function#c-in-visual-studio