fbpx

Azure Cloud Resume Challenge

Written By Craig Wall

Diving Right In To Get Familiar With Azure

 

Gwyneth Peña-Siguenza, a Microsoft Azure MVP and Community Training Architect at A Cloud Guru, is in charge of running the latest installment of their Cloud Resume Challenge, this time using Azure.

While it’s not directly in the wheelhouse of the AZ-104 that I’m studying for, I thought this was a great opportunity to get myself used to using Azure and Github, so I gave it a shot!

 

My Completed Page

https://cloudresume.helpmeihavetwins.com

I know, I know — weird URL. 

I have a domain for my Instagram account (help.me.i.have.twins) that I’m not actively using, so I decided to make use of it. 

 

What I liked — And What I Didn’t

 

The easiest part for me was the website creation and editing itself. I work a lot with WordPress so this was easy.

The hardest part for me was getting the Function App to work properly. Much of the holdup came from me following a tutorial that turned out not to work properly — but the process of me figuring that out turned out to be a benefit in itself.

All in all, I found this to be a great confidence booster for my ability to work in the cloud. This took plenty of “banging my head on it” time to figure portions out, and I’m happy with myself for sticking with it until I worked it out.

 

What Was Involved In the Challenge?

The overall goal was to host a resume webpage, in Azure.

The challenge entailed doing the following:

  1. Creating a Github Repo for my website
  2. Using Github pages to create the site there.
  3. Deploying that site from Github to Azure Blob Storage
  4. Adding a Javascript-based visitors counter to the site
  5. Pointing a custom URL to the site
  6. HTTPS-enabling the site
  7. Setting up Github to automatically publish any changes I make to the site to Azure

I’m very familiar with WordPress and the backend of web hosting, but I’ve never used the cloud to host a site before.

How much time this took: I’m a dad of 4 year old twins with a full time remote IT job, so with that in mind, this took about 4 days worth of free time.

The real pain in the butt here was the Javascript counter.

 

First off: The Azure Account I Used

A while ago I signed up for the Microsoft 365 Developer Program.

I did this because Linux Academy’s (and now a Cloud Guru’s) Cloud Sandboxes don’t support Azure Active Directory, but this program comes with a development Azure Tenant that does, for free.

I don’t believe this account gives me access to anything special for the sake of this challenge versus a student account or anything, but it’s worth mentioning even as an aside that the Developer Program might be worth joining.

 

Creating the Website

I started by creating a Github repo for my project.

I then downloaded Github desktop and copied the repository to my local machine.

This allowed me to easily add the repo as a workspace within Visual Studio Code.

I selected the Resume bootstrap theme. Downloaded it and threw the files into the Github repo, and committed the changes.

In the Github Repo, I activated Github Pages.

My site at this point was now active on Github: https://craigtwall.github.io/website/

All good so far, right? Well this was the easiest part of the challenge!

 

Copying the Website Into Azure Blob Storage

I uploaded my site to Azure Blob Storage without using Github – at first.

When I needed changes done to the HTML or JS files, I would do it in the portal, in the storage container.

Later, I would sync these up so that my Github repo would publish to Azure. But that’s not how I started.

 

In the Azure portal, click Create a Resource, search for and select “Storage Account”.

  • Choose your subscription and resource group
  • Create a globally-unique name
  • Standard Performance

Once the storage account exists, click Go To Resource.

On the left sidebar of the storage account options is “Static Website”.

By default this is disabled. Click enabled. Keep the Index and error document paths as is.

Azure will assign a primary endpoint HTTPS address, and will create a $web container to store the website files:

Click the $web link here (or click “containers” in the left sidebar”) to open the container.

I only had a few files to upload here — the website files from my github repo, so this was just a matter of uploading them straight in.

At this point, my website was available on the static website endpoint: https://ctwfunctionstorage.z13.web.core.windows.net

I would have to go into the $web container and edit the HTML and JS files directly if I wanted to update it, as it wasn’t tied to Github yet, but at least it was up there.

 

 

 

The Journey to the Visitors Counter

This took me a good two days of free time.

I just thought, okay, let’s find someone else’s blog post who’s done this and see what we can learn.

And I found someone who did. Excellent!

Sort of. Part of his code didn’t work correctly, and because I was still learning how all of this worked, I wound up rebuilding a portion of this a few times out of frustration.

I’ll run through what happened and what I wound up doing:

 

Building the Database: Azure Cosmos DB

In the Azure search bar, search for and select “Cosmos DB”. Then select Create.

There’s a Free Tier option if you have “provisioned throughput” selected for Capacity Mode. For this resume challenge, the free tier was fine.

Once it’s created, click Go To Resource, then Data Explorer.

My Free Tier database came with a pre-created database (ToDoList) and container (Items). When I created this database on my Azure For Students account, it didn’t come with anything pre-created, so keep that in mind.

In the database, click on Items and select New Item.

All I needed in the right panel here was “id” as Visitors, and “count” as 0. When I clicked update, it added some other stuff. I’m not going to pretend to know what the extra stuff is yet.

 

Using Azure Function to make a Javascript Counter Work

On the Azure Portal, search for and select “Function App”.

Select your subscription and resource group, create a globally unique Function App name.

I chose Node.js as the runtime stack and left Version and Region as the default.

When the Function App creation is finished, click Go To Resource.

Click Functions on the left sidebar, and then Add to Add a trigger.

I left the option to “Develop in Portal” instead of changing it to “VS Code”, which I was using to edit the website.

Click HTTP Trigger. Give it a name. For Authorization Level, use Function.

I chose to “Develop in Portal” just to cut down on the confusion I caused myself by getting the hang of creating local functions with VSCode. I decided, heck with this, I’m starting over, I’m just going to throw the site up and create the function while the site’s already in Azure.

A few other tutorials went a different route: creating the function locally using VS Code first, and THEN publishing that local function to Azure. The way I did it was kind of backwards.

When the Function is created, it will exist in the Function App’s Functions list, as seen in the image above. Click on the Function name.

Click Integration. A mostly-empty diagram shows up.

Under Inputs, select Create Input.

You can leave the Document name (inputDocument) alone.

  • Database Name must match the Cosmos DB database
  • Collection name needs to match the container name

Under Cosmos DB Account Connection, you may need to click the New link underneath to have a connection string generated.

Now here is where the one tutorial screwed me up: One tutorial put in a SQL Query here that generated a 500 error when the website loaded. The query was meant to specify which ID within the database container to select.

That’s what kept me busy for half a day: believing this query was necessary and that it had to be fixed, when it wasn’t really necessary.

I removed that query and left the box blank — I only created one ID within that database container, so it’s not a problem.

 

Now under Output, select Add Output. Again, make sure the database and collection names match up.

 

Back on the left sidebar, click Code + Test. The index.js file reads as below:


module.exports = async function (context, req, data) {
context.bindings.outputDocument = data[0];
context.bindings.outputDocument.count += 1;
context.res = {
body: data[0].count
};
}

The idea here is that “count” will match the “count” property in the database collection item we setup earlier. For each time this code runs, it will increment that “count” value by 1.

Click Test/Run and Run it, and you’ll see the numerical output:

 

Making the Website Counter Run

Okay, we have a working website counter function setup in Azure.

Now we need to call that sucker from the index.html page, and output the result to the webpage itself somewhere.

 

The URL to Call the function from the webpage

In the Code + Test section of the Trigger we just made, there is a Get Function URL” button.

Click that button, and copy the function key. That key is the URL we need to call, using Javascript, from the webpage.

 

THE CORS Function App SETTING

Under the Function App, click CORS on the sidebar.

CORS is a setting on the Function App which lists URLs that are allowed to interact with the backend.

Your static URL website needs to be on the list. Add it in.

 
Update the Javascript file to invoke the Function App

When the website loads, my theme’s Index.html calls “main.js”.

Main.js calls the Function app, receives and handles the output.

The easiest template to point you to is the main.js from Gwyn’s own Github.

The FunctionApi variable points to the “Function URL” that we copied from the Function trigger earlier.

 

Where I Got Tripped Up:

Gwyn’s example uses:

count = response.count; 
document.getElementById('counter').innerText = count;

This assumes that what is returned is a JSON object with a property of “count”.

When I tried this, I kept getting “undefined” printed out on the webpage.

The reason why: When we tested the function earlier, what was returned was an integer.

Not an object with a “count” integer inside of it — just the integer.

Gwyn’s example assumes an output JSON object that has a “count” attribute as part of it. Mine just returns the number. So instead of using “response.count”, I just used “response”.

count = response; <br />document.getElementById('counter').innerText = count;

 

Enabling Custom Domain Support With HTTPS

Okay, at this point of the project, we have a working website, on our static website endpoint, that will show a Javascript-based page counter.

The next step is to get a custom domain pointed to it, and working on HTTPS.

 

Why Azure CDN Was Used For This Project

HTTPS is already active on our static website endpoint — perfect! All I need to do is attach a custom domain, right?

Eh, not quite. Turns out, HTTPS support for custom domains requires us to setup Azure CDN, and enable the custom domain through the CDN.

When the CDN is setup, it will create a separate “endpoint” (URL) for the cached version of the site. For HTTPS support, that endpoint is what the custom domain has to point to.

  • Create a New CDN Profile

In the Azure Portal, go to Create a Resource. Search for and select CDN.

Give the profile a globally-unique name. Select your subscription and resource group. For pricing Tier, select Standard Microsoft.

 

Registering the CDN If It’s Unavailable

When I first tried to create a CDN profile, I received an error that looks like this:

“In order to create this CDN profile, please ensure that Microsoft.CDN is listed as a registered Resource Provider in your Azure Subscription.”

The solution is documented here on MS Docs. A one-liner using Azure CLI:

az provider register –namespace Microsoft.Cdn

 

 

Create a New CDN Endpoint

With a CDN Profile created, click into that profile, and click the “+ Endpoint” button to create a CDN Endpoint.

Create a unique name. Origin Type should be Storage Static Website. Your static website URL should be listed in the Origin Hostname pulldown box.

Keep the path blank.

The Origin Host Header should match the origin hostname.

Keep the HTTP/S ports at 80 and 443.

Optimize for general web delivery.

Once this is created, back on the endpoint’s Overview screen, you’ll see your Endpoint Hostname and the Origin Hostname that it’s mapped to.

At this point my website is now up and running at the CDN Endpoint URL, https://cdn-craigtwall-resumechallenge.azureedge.net . The URL’s index.html is a cached mirror of the static website’s index.html.

 

Add the CDN Endpoint to CORS in the Function App

If you’re testing the site at this point on the CDN endpoint, you’ll notice that the Javascript page counter doesn’t work anymore.

If you hit F12 in Chrome and use the Chrome dev tools, the console will probably spit out that the JS call was blocked by CORS policy.

To test the counter on the CDN endpoint, go back to the “CORS” section of your function app, and add the Endpoint Hostname URL to the list of allowed URLs.

 

 
Google Domains – Setup CNAME DNS Records 

I followed the “Zero Downtime” portion of this, which involved creating two DNS CNAME records.

I have an old Domain name for my Instagram account, helpmeihavetwins.com, that I wasn’t actively using.

So in Google Domains, I created:

  • CNAME for asverify.cloudresume, pointing to asverify.(my storage endpoint URL)
  • CNAME for cloudresume, pointing to my CDN Endpoint URL.

 
Pre-Register the Domain Name in Azure

(Optional)

While I did this step, this doesn’t appear to have been necessary to get the site up and running. 

 

In the Azure Portal, go to your Storage Account, then the Networking option.

On the Networking page, choose Custom Domain.

Add in your custom domain here. For me, it was cloudresume.helpmeihavetwins.com.

Check the box that says “Indirect CNAME Validation”.

This will verify the domain, but won’t route traffic to the URL just yet.

 
Register the Custom Domain in the CDN Endpoint

In the Azure portal, go to your CDN profile, then click on your CDN endpoint.

Click Custom Domains. Then the “+ Custom Domain” button.

In the Custom Hostname box will go your custom domain. For me, this was cloudresume.helpmeihavetwins.com.

The system will check for a valid CNAME record on your domain before it allows you to confirm it.

 
Enable HTTPS on the Custom Domain

Once this is confirmed, go back to the CDN Endpoint and click on Custom Domains.

Click the Custom Domain you just verified.

Click to Enable Custom Domain HTTPS.

Use a CDN-Managed Certificate and keep the TLS version at 1.2.

The certificate will take a little time to deploy, after which your website’s custom domain will now work.

https://cloudresume.helpmeihavetwins.com

 

CORS – ADD YOUR CUSTOM DOMAIN

Back in the “CORS” section of your Function App, make sure your custom domain has been added to the list of URLs. Otherwise you will once again notice that the page counter has stopped working.

 

FINALLY: Auto-Updating the Site Via Github

The Azure-based site is done at this point, but there’s one final task: set Github up to automatically update the site when I make changes.

First I had to copy the contents of index.html and main.js back to the copy of my site I had locally — I’d edited both in the Azure portal in order to get the Javascript counter function working. 

Then, I used the above walkthrough to setup Github actions on my repo. 

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *