Book Image

Advanced Serverless Architectures with Microsoft Azure

By : Daniel Bass
Book Image

Advanced Serverless Architectures with Microsoft Azure

By: Daniel Bass

Overview of this book

Advanced Serverless Architectures with Microsoft Azure redefines your experience of designing serverless systems. It shows you how to tackle challenges of varying levels, not just the straightforward ones. You'll be learning how to deliver features quickly by building systems, which retain the scalability and benefits of serverless. You'll begin your journey by learning how to build a simple, completely serverless application. Then, you'll build a highly scalable solution using a queue, load messages onto the queue, and read them asynchronously. To boost your knowledge further, the book also features durable functions and ways to use them to solve errors in a complex system. You'll then learn about security by building a security solution from serverless components. Next, you’ll gain an understanding of observability and ways to leverage application insights to bring you performance benefits. As you approach the concluding chapters, you’ll explore chaos engineering and the benefits of resilience, by actively switching off a few of the functions within a complex system, submitting a request, and observing the resulting behavior. By the end of this book, you will have developed the skills you need to build and maintain increasingly complex systems that match evolving platform requirements.
Table of Contents (8 chapters)

Serverless Websites with Azure Storage


The final component of the basic serverless architecture is a client frontend. The most common one is web-based, but obviously mobile apps or chatbots are also used. We will be using a web-based frontend in this book.

This is the area that serverless is least developed in. The core idea, however, is to have some way of serving the raw HTML, CSS, and JS files to the client, and having JavaScript call the serverless backend from the client side. The only issue is where and how to host those HTML files.

There are multiple approaches to this. Many applications will be expanding on a current platform, perhaps a CMS such as Adobe Experience Manager, Wordpress, or Sitecore CMS. In that case, the best approach is likely to be embedding your frontend application as a JavaScript Single Page Application in a framework such as Angular, React, or Vue.

If working with a completely greenfield application where you can build a truly serverless application architecture, however, there are a greater range of options, which are listed in order of "serverless-ness" in the following list. One thing to be clear about, however, is that this isn't a fully solved problem yet, so each option will have some disadvantages that will hopefully be fixed over time:

  • Use Azure Storage Static Website Hosting: This has very recently come out of preview, and is now in General Availability. It may be a little unstable given how new the feature is. This feature allows you to use Azure Storage as the repository for your HTML, CSS, and JS files, and set a default home page and a default error page. This is the most serverless option as there are no implementation details or management requirements whatsoever—you can literally put your frontend code there and it will work. This will be the option we will follow in this book.

  • Serve files using an Azure Function: The second option is to use an Azure function as a way of hosting your HTML, CSS, or JS files. If you put your HTML code files into the C# project, you can reply to any HTTP Trigger with them. Azure Functions have standard IIS routing too, which can be used to route to the different pages. This has a few disadvantages though: Azure Functions are charged per gigabyte of RAM per second, so using them to simply transfer potentially large files isn't ideal (as that file will be loaded into the RAM and will need to be encoded and decoded, resulting in needless expense). Also, it isn't very serverless—this solution requires custom, non-business-value-oriented code just to serve up web pages. It will, however, scale along with your serverless backend, and Azure Functions are more mature than Azure Storage Static Website Hosting.

  • Deploy Files to an Azure App Service: The third option is to deploy the files to an Azure App Service. This Platform-as-a-Service technology is well-suited to this task and can host more complex MVC applications as well. They can also scale horizontally without management, which is advantageous. However, the number is limited depending on how "big" a resource you demand. The major issue is the level of management and implementation detail. All we want as serverless developers is a bucket to put files in, and Azure's App Services have all sorts of details we aren't interested in, for example, the number of virtual cores on each instance or the RAM currently being used. One point in their favor for small projects though is the "free" category of hosting, which allows you to deploy a custom web app to the internet for free. This is really useful for prototypes, too.

As you can see, the options progress in management level, adding more and more effort expended into non-business value activities. This is without going down to the level of maintaining a virtual machine or a Kubernetes cluster or, even worse, a physical machine in a rack.

Note

There is in fact a fourth option for utilizing AWS. The storage service in AWS is called S3 and has a fully supported static website hosting feature, which you can read about here: https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html. There aren't any compatibility issues in doing this—latency isn't even an issue as users will be calling the Azure Functions' endpoints from their browsers. Lambda (AWS's FaaS service) can also serve files like Azure Functions.

Exercise 3: Hosting a Serverless Website on Azure Storage

The aim of this exercise is to host a simple Hello World! page on Azure Storage, thus creating a serverless website:

  1. First, you need files to host. Create a new folder called ServerlessWebsite in your development area and create new index.html and error.html files in there:

    Figure 1.29: Empty website files

  2. Create a simple page for both the index and error. The following code can be used to display Hello World!:

    <html>
    <body>
        <h1>Hello World!</h1>
    </body>
    </html>

    The following example can be used to display Error:

    Figure 1.30: Error page

  3. Now that you've created the files to host, let's create an account on Azure Storage where you can host these files. Open the Azure Portal and search for "storage":

    Figure 1.31: Searching for storage

  4. Select Storage accounts. You should see a screen like the one shown in the following screenshot, with at least one storage account already existing from when you created it. You may see more if you have already been using Azure and have already made some storage accounts:

    Note

    It's possible that you will see other categories of storage account in the search, such as classic. This depends on your Azure Account, so you won't necessarily see any others. Just always select the one that precisely says Storage accounts.

    Figure 1.32: Azure Storage Accounts page

  5. Click Add. You should be taken to a screen like the one shown in the following screenshot. Enter the same resource group that you did for Cosmos DB and the Azure Function App. Give your storage account an appropriate name for hosting a website (the one in this exercise is named webfrontendadvanceds). Choose a location near to you. Choose Standard performance, StorageV2, and simple Locally Redundant Storage or RA-GRS. In production, you will probably want a greater level of georedundancy, but for development purposes, locally redundant storage is fine. Premium performance is actually designed for virtual machine disks, not for web hosting, and is not currently supported with static site hosting. Finally, choose the Hot access tier; Cold is for archiving data:

    Note

    Note that storage account names have to be globally unique. Hence, do not try and create a storage account with the exact same name as the one that's used in this exercise.

    Figure 1.33: Creating a storage account

  6. Click the Review + create button and then create the storage account. This may take a little while to provision. You will receive a notification in the top right of the page when it has been created:

    Figure 1.34: Creating a storage account

  7. Now, you can host the files you created on your Azure Storage account. Go to the storage account you just created (it will appear on the pane on the left) and click on it:

    Figure 1.35: Storage Account Home

  8. Scroll down the left column and look for Static website (preview) under Settings. Enable it and set your Index document name to index.html and your Error document path to error.html, as shown in the following screenshot:

    Figure 1.36: Setting up static website hosting

  9. Click on the Azure tab. We are going to use the Azure Storage extension of Visual Studio Code to deploy the site. Click the Azure Storage account and open the Blob Containers sub-item until you get to the $web item. Right-click it and select Deploy to Static Website:

    Figure 1.37: Deploy to Static Website

    Note

    Using the Azure Storage extension of Visual Studio Code is the easiest manual way to upload files to Azure Storage. If you are doing an automated deployment, you should use a PowerShell script to connect.

  10. You will now be prompted to select a folder to deploy. Select the ServerlessWebsite folder:

    Figure 1.38: Selecting a folder to deploy

  11. Click Delete and Deploy if the following message comes up. It won't if you have never deployed anything to this Azure Storage account before:

     

    Figure 1.39: Confirming deployment

    As before, updates on the deployment will appear in the bottom right:

    Figure 1.40: Deployment updates

  12. You can finally test your website by visiting the address of your Azure Blob Storage account in your browser. This can be found by clicking on the browse site button in the successful deployment update, going back to the static website part of the portal, or by using the pattern they all follow: https://{StorageAccountName}.z6.web.core.windows.net:

    Figure 1.41: Serverless website hosted on Azure Storage

You now have the fundamental building blocks of a complete serverless architecture. With Azure Storage hosting your website, you can build any web application. Of course, other client-side delivery methods such as mobile apps and chatbots are possible. Mobile apps are a perfect fit, simply calling the serverless backend directly. Chatbots would use Alexa or Google Assistant as their frontend and call in to the serverless backend.

Exercise 4: Displaying Product Data on Your Serverless Website

In this exercise, you will be displaying product data from the serverless database (Cosmos DB) on the serverless website hosted in the Azure Storage, using the Azure Function you created in the first exercise. It will serve as the basis for the rest of your work on this book, and an inspiration for how easy and quick this development process is:

  1. First of all, you need some product data to display. Go to the Cosmos DB instance in the Azure Portal and select Data Explorer:

    Figure 1.42: Cosmos DB Data Explorer

  2. Click on the New Database option to create a database. Call it serverless and click on OK:

    Figure 1.43: Creating a database

  3. Next, click on the New Collection option and create a collection called products in the serverless database that we created in the preceding step. Set its throughput to 400 Resource Units (this is how Cosmos DB charges for compute usage on queries) and set the Partition key to /colour. Again, click on OK:

    Figure 1.44: Creating a collection

  4. Click on Documents inside the Collection, as shown in the following screenshot:

    Figure 1.45: Selecting Documents inside the collection

  5. Click on the New Document option. Insert some records into the Cosmos DB, which will represent products. An example is shown in the following code. Make sure that you do not remove or misspell any of the property names as it will cause problems later. The ID follows the pattern {typeId}_{name}_{colour}_{size}. Cosmos DB will add some fields, including a very useful Etag, which will be used later. In general, you don't need to worry about the automatically added fields; Cosmos DB will handle them:

    {
        "id":"tshirt_metallica_black_xl",
        "typeId": "tshirt",
        "name": "Metallica",
        "colour": "black",
        "size": "xl",
        "quantityInStock": 100
    }

    Figure 1.46: Creating a Cosmos DB record

    You have now added your product data to Cosmos DB. Now, you need to display this data on your website using the Azure function we created previously.

  6. Open the GetProducts Azure Function from Exercise 1, Creating an Azure Function. Install the DocumentDB package by opening the terminal in the ProductsApi folder and entering the following command:

    dotnet add package Microsoft.Azure.WebJobs.Extensions.CosmosDB --version 3.0.1

    Note

    Due to version upgrades, the latest version may not exactly match the one given here. We recommend that you use the latest version for this and the subsequent exercises and activities, in order to ensure that the command functions.

    Next, we need to ensure that all the NuGet packages are installed, which we do by "restoring". Use the following command:

    dotnet restore

    Your file will look as follows:

    Figure 1.47: Installing the DocumentDB extension

  7. We need to give our function the ability to read from the Cosmos DB. This is done using a DocumentClient object from the SDK. Add a using statement for Microsoft.Azure.Documents.Client and create a private static DocumentClient property called client:

    private static DocumentClient client = new DocumentClient(new Uri("cosmos endpoint"),"key");

    Figure 1.48: Added DocumentClient

  8. Next, we need the Unique Resource Identifier (URI) for the Collection inside the Cosmos DB instance. This will allow us to create queries against that collection. Create a private static Uri property that uses the UriFactory to create a URI for the DocumentCollection:

    private static Uri productCollectionUri = UriFactory.CreateDocumentCollectionUri("serverless","products");

    Your file will look as follows:

    Figure 1.49: Adding productCollectionUri

  9. Add a private static QueryOptions property with the MaxItemCount set to –1. This sets the number of docs returned in a query to infinite, which is something to be cautious of as your database scales:

    private static readonly FeedOptions productQueryOptions = new FeedOptions { MaxItemCount = -1 };

    Figure 1.50: Adding productQueryOptions

  10. Now, we need to return the products from Cosmos DB. We don't need the post method anymore, so delete post from the function signature. Change the return type to Task<List<Product>>. The Cosmos DB SDK uses an Iqueryable syntax that lets you use LINQ expressions in C# to generate queries on the database. This is superb for simple queries, but it is advisable to double-check what database queries it is generating for complex queries as they may not be optimally efficient. We will use the syntax to simply return all. Delete the entire function body and replace it with this:

    return client.CreateDocumentQuery<Product>(productCollectionUri, productQueryOptions).ToList();

    Also, add the following using statement:

    using System.Linq;

    Figure 1.51: Adding query returning products

  11. Add a Product class in a file called Product.cs in a folder called Models with properties matching the ones in the Cosmos DB. Add a JsonProperty annotation on the ID property to force it into lower case:

    Figure 1.52: Product Model

  12. Add the following three using statements to the GetProducts function:

    using System.Collections.Generic; using ProductsApi.Models;
  13. Now, go to Cosmos DB in the Azure Portal and click on Keys. Retrieve the endpoint and the primary key and enter them into the DocumentClient. This is vital to authorize your function to connect to your Cosmos DB.

  14. Test the function by pressing the play button on the debug tab and going to the address in your browser. You should see an output similar to the following when testing:

    Figure 1.53: Testing the function

  15. Open the ServerlessWebsite folder in VS Code. Add a table to the index.html file using the following code:

    <table>
        <thead>
            <tr>
                <th>
                    Name
                </th>
                <th>
                    Size
                </th>
                <th>
                    Colour
                </th>
                <th>
                    Quantity In Stock
                </th>
            </tr>
        </thead>
        <tbody id='tableBody'>
        </tbody>
    </table>

    Figure 1.54: HTML Table

  16. Add a function that takes the object from the API and returns a table row by using the following code:

    <script>
        function rowOfDataFromObject(data){
            let row = document.createElement('tr');
    
            let nameTableElement = document.createElement('td');
            nameTableElement.appendChild(document.createTextNode(data.name));
            row.appendChild(nameTableElement);
    
            let sizeTableElement = document.createElement('td');
            sizeTableElement.appendChild(document.createTextNode(data.size));
            row.appendChild(sizeTableElement);
    
            let colourTableElement = document.createElement('td');
            colourTableElement.appendChild(document.createTextNode(data.colour));
            row.appendChild(colourTableElement);
    
            let quantityTableElement = document.createElement('td');
            quantityTableElement.appendChild(document.createTextNode(data.quantityInStock));
            row.appendChild(quantityTableElement);
    
            return row;
        }
    </script>

    Figure 1.55: Function that returns a table row from a product object

  17. Add a HTTP GET call to the Azure function either by running locally or in the cloud using the fetch method, and turn it into a table row using the JavaScript method you just created (in the following screenshot, the function being called is one that would be running locally as the address in the fetch method is a localhost address):

    Figure 1.56: Fetching product data from the Azure function

  18. Append the rows to the table using the ID set in the HTML and the table rows created by the method:

    document.getElementById("tableBody").appendChild(productRow);

    Figure 1.57: Appending rows to table

  19. Cross Origin Resource Sharing (CORS) is an important security measure that applies to Azure functions as well. It prevents scripts from unexpected websites calling your Azure Function. For the moment, though, this prevents us from testing effectively, so we are going to open it up to all. In production, you would give it only the addresses you expect, so this would be the URL of your website, for example. Open the ProductsApi folder and add a local.settings.json file if it isn't already there. Modify it to add an element called Host with a property called CORS with the value *:

    Figure 1.58: Setting CORS rules to permissive

  20. Finally, test your HTML page by opening it from your local disk or uploading it to Azure Storage and opening in your browser:

    Figure 1.59: Working web page displaying products

You've successfully created your first serverless application in only a couple of hours. This solution almost certainly scales better than anything most developers have ever made and required little extra effort from us.

Activity 1: Creating a Serverless Application for Viewing User Data

You are a developer working for Serverless Ltd. and you have been tasked with creating a serverless application for a client that lets them view basic data about the end customers of their clothing company. For this purpose, you need to create an end-to-end serverless app to view users. Follow these steps to complete this activity:

  1. Create a collection called users in the Cosmos DB database named serverless.

  2. Add some user data to it. The example object just uses name and email address:

    {
        "name": "Daniel",
        "emailAddress": "[email protected]"
    }
  3. Create an Azure function called GetUsers that reads from the users collection.

  4. Create an index.html file that displays that data on a web page by using JavaScript to call the Azure function:

    Figure 1.60: Resulting User Table

Note

The solution for this activity can be found on page 230.