Create and Configure an Application Gateway in Azure

Hands-On Lab

 

Photo of Shawn Johnson

Shawn Johnson

Azure Training Architect II in Content

Length

01:30:00

Difficulty

Intermediate

PLEASE BE AWARE: The Azure Portal has changed since this hands-on-lab was created. Most steps are now completed during the initial creation of the Application Gateway, rather than afterwards. This lab will be updated. You may continue to use it as-is, but please be aware that an update is coming soon Azure Application Gateway provides application-level routing and load-balancing services that let you build a scalable and highly-available web front end in Azure. From Level 7 web traffic routing, all the way to custom URL-based path rules, we will cover the benefits of Application Gateways and why you should choose them over traditional load balancers to route web traffic. Lessons Learned: - Create an Azure App Gateway using the Azure Portal - Configure Azure App Gateway backend pools, ports, and listeners - Create URL-based rule that routes traffic to different VMSS

What are Hands-On Labs?

Hands-On Labs are scenario-based learning environments where learners can practice without consequences. Don't compromise a system or waste money on expensive downloads. Practice real-world skills without the real-world risk, no assembly required.

Create and Configure an Application Gateway in Azure

In this lab, we're going to be creating and configuring an Application Gateway in Azure. What is an Application Gateway, you ask? An Azure Application Gateway is used to load-balance and direct web traffic to backend websites. While a traditional application gateway operates at OSI Level 4 (meaning that it routes traffic based on IP and port only), an Azure Application Gateway operates at OSI Level 7. It routes traffic based on an incoming URL, which means you can host multiple sites behind it, making an Azure Application Gateway very flexible.

The Lab Environment

In the learning environment, we've got an Azure resource group. It's fairly bare. It only has a virtual network, a storage account (which we'll be using for Azure Cloud Shell), and a public IP that we'll be assigning to the Application Gateway we create.

This lab has several steps:

  1. Configure Cloud Shell
  2. Copy the ID and location of the virtual network
  3. Create an Application Gateway
  4. Configure various load-balancing components:
    • Backend pools
    • A custom TCP port
    • A listener for the port
    • Routing rule based on URLs of incoming web requests
    • Deploy three separate VM scale sets
      • Each will consist of two VMs running Ubuntu 16.04
      • Each one will be responsible for various aspects of the website we're going to deploy:
        1. Handles index.html file
        2. Hosting of the /images directory
        3. Hosting of the /videos directory
  5. Install Nginx
  6. Configure a simple web app
  7. Test the Azure Application Gateway

Without further ado, let's get right into things. In the lab, you can see the login credentials on the left. On the right is a View Architectural Diagram button. Click that, and the same diagram that's in the lab video will pop out for you to look at. You may be better off actually downloading that image and having it open as a reference as you proceed through the lab's tasks.

On the lower left, there is a list of objectives (which are also outlined, but not quite verbatim, above in this guide) that make up the lab. There are a lot of list items. Be warned, this lab will take some time. Creating the Application Gateway alone will take about 15 minutes. Configuring some of the other things take about five minutes apiece. So make sure you've got a good-sized block of time to work on this.

Once you're ready, let's go ahead and log in to the Azure portal with the provided credentials. We can skip the tutorial, and we'll be ready to go.

The Lay of the Land

Let's take a look at our Azure resources. As we saw earlier, it's a pretty bare-bones setup. We have a public IP address that we'll assign to the Application Gateway when we set it up, we have a storage account that we'll be using with Azure Cloud Shell, and we have a virtual network. Let's start knocking things off the list of objectives.

Configure Cloud Shell

In the Azure Portal, click on the button up at the top of the screen for Cloud Shell and choose Bash from the bottom frame that opens up in the browser window. When we set up a Cloud Shell, it needs a storage account so that it can hold temporary data, like history and anything you download in the shell.

By default, clicking Create storage will create a new storage account for you with a resource group attached. But we want to use the one that's already been set up for us in the lab. Click Show advanced Settings. The Subscription, Resource group, and Storage account have all been set for us. But we've got to make sure we're in the right region, so set Cloud Shell region to South Central US. Once that takes hold, we'll be able to click the Use existing for a Storage account. Then the only thing left to do is provide a File share that the Cloud Shell is going to use. We've already got one, but this field isn't populated automatically, so we've got to type it manually. Make sure to click on Use existing, type cloudshell, and then click Attach storage. cloudshell was the file share provisioned for us when the lab spun up.

Clicking the button is going to fire up a Bash terminal window, with information about the creation of the cloud drive. We'll be sitting at a command prompt at the end of it all. We can leave the window open, but shrink it out of the way so we can continue on. The Cloud Shell is all set up.

Copy the ID and Location of the Virtual Network

When our lab environment is deployed, every resource is appended with a unique ID. We'll use that ID for the rest of the resources we deploy in this lab. In All resources, click on the Virtual network, and then in the next screen, copy the suffix text (everything after vnet-) that is sitting up toward the top of the screen.

Notice the location of the virtual network. When we create the Application Gateway, it needs to be in the same location as the public IP and the resource group for all of the other objects. This virtual network is in South Central US.

Create an Application Gateway

This is the biggest task of the lab. In the Azure Portal, click the green + icon to create a new resource. Type Application Gateway in the search box that currently says Search the Marketplace. Click on the blue Create button in the lower left. There are a few fields we have to fill in on the next screen:

  • Name: agw-<PASTED SUFFIX> (that needs to be the suffix we copied earlier).
  • Tier: Standard is fine.
  • Instance count: 2 is good.
  • SKU size: Medium is fine here.
  • Subscription: This won't change either.
  • Resource group: Select the existing one that was provisioned for us.
  • Location: Make sure to change this to where our virtual network is, South Central US.

Click the blue OK button to proceed. Now we'll configure some Application Gateway specific settings.

At the top of this next screen, let's click on the Virtual network flyout, and choose the one that's been provisioned for us. Notice the Subnet gets set automatically. There are two subnet options in there though. Remember that our backend servers have to reside on a separate subnet than our Application Gateway. Let's choose snet1-<SUFFIX>, and we'll make sure to stick the virtual machine scale sets on the other subnet when we deploy.

We're going to set IP address type to Public, and select Use existing in the Public IP address section. That dropdown should autopopulate with the IP that was provisioned for us.

As far as Listener Configuration goes, we need to set the Protocol to HTTP, the Port to 80, and leave the rest of the settings alone. We can click OK here, and then review the information on the next page. If everything looks good, we can click OK here too.

This will start the deployment, and it's about a 15-minute process. There's no way around it. Now is a good time to get a coffee or take a real quick nap. You'll know when it's done when you get a Deployment succeeded message in your notifications.

Once we're back, let's go look at the newly deployed Application Gateway by clicking on the bell icon at the top of the Azure Portal screen, and clicking the blue Go to resource button.

We've got our Frontend public IP address that was associated to the Application Gateway when we created it. The Virtual network/subnet shows that it's sitting in our virtual network on the correct subnet. We're looking good.

On to the next objective.

Configure Backend Pools

These are going to be separate pools to host our virtual machine scale sets. One will be for images, and the other for videos. When we created the Application Gateway, it came with a default backend pool. We're going to use that for our first virtual machine set, and it will host our index.html file.

From the Application Gateway page, we can click on Backend pools (in the left menu, under the Settings section). We'll see the default one already sitting there, with one default routing rule and no targets.

Click Add up at the top, and then enter imagesBackendPool into the Name box. Let's go ahead and check the Add backend pool without targets box, and just set them later when we create the scale sets.

Click Add again. Rather than wait for the Application Gateway to update with the pool we just created, we can keep moving and create other things. Microsoft allows people to make changes on top of changes, and those changes are included in previous changes that were made.

Click Add at the top of the page again, and enter videoBackendPool as the name of our next pool. Check Add backend pool without targets again, and click the blue Add button down at the bottom again.

You'll see some notifications start showing up as you do things. One of them looks like an error, or a warning, about an operation being superseded. These are fine. It just means that what we're doing, adding more things to the gateway, is taking effect.

If we wait for each operation to complete before moving to the next one, we wouldn't see those messages. But the lab would expire before we're finished. So we're going to just keep moving, set all of these things up, and understand that they are happening in the background.

To see what has actually taken effect so far, click on the Refresh button. After a couple of minutes here, we should see the images and video backend pools.

Let's get on to the next objective.

Use the Azure CLI in the Cloud Shell to Configure a Custom Port

We're going to configure a custom port with a Bash script. This is the first of a few scripts we'll be using to do a few different things. Here's what's in the script:

rgName=$(az group list --query '[].{name:name}' --output tsv)
agwName=$(az network application-gateway list --query '[].{name:name}' --output tsv)
az network application-gateway frontend-port create 
  --port 8080 
  --gateway-name $agwName 
  --resource-group $rgName 
  --name port8080
#

This one created a custom front end port. Right now, the Application Gateway is already listening on port 80, but we want it listening on 8080 as well. This script will make that happen. Let's take a look at it line by line.

These first two lines call az list commands. The first one will return a list of resource groups that we have access to, and assigning that resource group name to our rgName variable. The second does the same thing, except it will be assigning the Application Gateway name to the agName variable:

rgName=$(az group list --query '[].{name:name}' --output tsv)
agwName=$(az network application-gateway list --query '[].{name:name}' --output tsv)

The next few lines of the script are all one command. This is the command that creates the front end port:

az network application-gateway frontend-port create 
  --port 8080 
  --gateway-name $agwName 
  --resource-group $rgName 
  --name port8080

This last line is a hash, sitting all by itself. It keeps us from having to hit Enter after we paste the whole script into Cloud Shell:

#

We should still have a Cloud Shell window open. Get back into that, and paste in that whole script. That's going to take a little while to finish, so let's move on to the next objective. Minimize the Cloud Shell window again.

Create a Backend Listener in the Azure Portal

Back in the Application Gateway page, click on Listeners. Here, we can see a default listener already set up for port 80 and assigned to the Application Gateway. We've got to set one up for 8080 though. Click Basic to add a basic listener.

There's a form to fill out here, but most of it is already populated. We've got to plug a Name in (use backendListener), and leave the Frontend IP configuration set to appGatewayFrontendIP. Our script is still running, but it did already create a port, and we can see it (port8080) in the Frontend port dropdown. We'll leave that, and keep the protocol set to HTTP, then click OK down at the bottom of the page.

We can see right away on the Listeners page that the backendListener has been created.

Back in the Cloud Shell window, we'll see that it looks like the deployment failed. But if you look closer, you can see that it's a superseded by operation type of message. This is similar to what we saw in the portal messages, and isn't anything to worry about.

We can move along to the next objective.

Create a Path-Based Rule in the Azure Portal

This rule we're about to create will take our specific URLs and route them to the appropriate scale sets. Let's go ahead into the Rules section of the Application Gateway, and click on the + Path-based button to add a new path-based rule.

For a Name, we'll specify rule2. We'll use the backendListener as a Listener, appGatewayBackendPool (this got created when we created the Application Gateway) for the Default backend pool, and select appGatewayBackendHttpSettings for the Default HTTP settings dropdown.

In the next section down, we'll specify the names and paths we'll be using to redirect traffic to our scale sets. In this line of four boxes, enter the following information:

  • NAME: imagesPathRule
  • PATHS: **/images/***
  • BACKEND POOL: imagesBackendPool
  • HTTP SETTING: appGatewayBackendHttpSettings (this is already set by default)

As soon as you started typing in that line, you may have noticed a new line of boxes form underneath it. Let's go into that second line now, and enter these values:

  • NAME: videoPathRule
  • PATHS: **/video/***
  • BACKEND POOL: videoBackendPool
  • HTTP SETTING: appGatewayBackendHttpSettings (this is already set by default, like the images one was)

Now that those lines of boxes are filled in, we can click OK down at the bottom of the page again and continue on. Back on the Application Gateway page, there will be another superseded by operation message popped out, which is still OK. We can see that rule2 has been created, and we're just waiting on the Application Gateway to update itself.

This step is a little different than some of the others before it. We actually want our Application Gateway to be all done updating before we commence. So we've got to wait a bit. Take another break or a nap (a shorter one this time though) and come back in a few minutes.

Create VM Scale Sets

Our Application Gateway is all updated, so we can close the notifications window. Now we're ready to actually create and deploy our scale sets. There are three:

  • myvmss1 will host index.html.
  • myvmss2 will host /images/*
  • myvmms3 will host /video/*

This is the script we'll need for deploying three virtual machine scale sets that will host our web data:

rgName=$(az group list --query '[].{name:name}' --output tsv)
vnetName=$(az network vnet list --query '[].{name:name}' --output tsv)
snetName=$(az network vnet subnet list --resource-group $rgName --vnet-name $vnetName --query "[?contains(name, 'snet2')].{Name:name}" --output tsv)
agwName=$(az network application-gateway list --query '[].{name:name}' --output tsv)

for i in `seq 1 3`; do

  if [ $i -eq 1 ]
  then
    poolName="appGatewayBackendPool"
  fi

  if [ $i -eq 2 ]
  then
    poolName="imagesBackendPool"
  fi

  if [ $i -eq 3 ]
  then
    poolName="videoBackendPool"
  fi

  az vmss create 
    --name myvmss$i 
    --resource-group $rgName 
    --image UbuntuLTS 
    --admin-username azureuser 
    --admin-password Azure123456! 
    --instance-count 2 
    --vnet-name $vnetName 
    --subnet $snetName 
    --vm-sku Standard_DS1_v2 
    --upgrade-policy-mode Automatic 
    --app-gateway $agwName 
    --backend-pool-name $poolName

sleep 20s

done
#

Before we enter it into Cloud Shell, though, let's walk through it line by line, just like the last big one we ran.

Line 1 should look familiar. It's the same line that was in the last script. It will return a list of resource groups that we have access to, and assigning that resource group name to our rgName variable.

rgName=$(az group list --query '[].{name:name}' --output tsv)

Line 2 does the same kind of thing, except it's getting the name of our virtual network and setting it as a vnetName variable.

vnetName=$(az network vnet list --query '[].{name:name}' --output tsv)

Lines 3, 4, 5, and 6 are actually one line, split up with ` characters (to make it easier to read). They are reading the name of the subnet that we're going to be deploying the subnets into, and setting that name as thesnetName` variable.

snetName=$(az network vnet subnet list 
              --resource-group $rgName
              --vnet-name $vnetName
              --query "[?contains(name, 'snet2')].{Name:name}" --output tsv)

Line 7 should look familiar, too, as it was also in that first script. It will be assigning the Application Gateway name to the agName variable.

agwName=$(az network application-gateway list --query '[].{name:name}' --output tsv)

Lines 8 through 35 are a for loop that is going to repeat three times. It repeats three times, because we're going to be creating three virtual machine scale sets with it.

Zooming in a bit on that section, lines 9 through 20 state that if the last character of the scale set is 1, 2, or 3, then we're going to set a variable called poolName to a separate or different backend pool in the Application Gateway. This ensures each virtual machine scale set is going to get deployed in a different backend pool.

for i in `seq 1 3`; do

  if [ $i -eq 1 ]
  then
    poolName="appGatewayBackendPool"
  fi

  if [ $i -eq 2 ]
  then
    poolName="imagesBackendPool"
  fi

  if [ $i -eq 3 ]
  then
    poolName="videoBackendPool"
  fi

Lines 21 through 33 is the az vmms create command, which creates a virtual machine's scale set.

  az vmss create 
    --name myvmss$i 
    --resource-group $rgName 
    --image UbuntuLTS 
    --admin-username azureuser 
    --admin-password Azure123456! 
    --instance-count 2 
    --vnet-name $vnetName 
    --subnet $snetName 
    --vm-sku Standard_DS1_v2 
    --upgrade-policy-mode Automatic 
    --app-gateway $agwName 
    --backend-pool-name $poolName

Line 34 sleeps for 20 seconds between each of the three iterations in the for loop. If you don't have this line, you may run into trouble when creating multiple scale sets.

sleep 20s

Line 35 ends the for loop, and line 36 is a simple hashtag that keeps you from needing to hit Enter after pasting this script into Cloud Shell.

done
#

So, we'll open Cloud Shell again, resize our terminal window if we need to, and paste that whole script in. The script should take about five minutes to run.

You haven't got enough time for even a short nap here, but there is a big enough window to snag a quick cup of coffee.

Once our script is done, let's minimize the Cloud Shell window and head back over to the All Resources Portal, where we can see all three myvmss scale sets up and running.

Install Nginx

The final step to setting up our environment is deploying an Nginx web server and installing some very simple HTML code to each of these scale sets. We're going to do that with yet another shell script. Here it is, in its entirety:

rgName=$(az group list --query '[].{name:name}' --output tsv)

for i in `seq 1 3`; do
 az vmss extension set 
   --publisher Microsoft.Azure.Extensions 
   --version 2.0 
   --name CustomScript 
   --resource-group $rgName 
   --vmss-name myvmss$i 
   --settings '{ "fileUris": ["https://raw.githubusercontent.com/linuxacademy/content-az-300-lab-repos/master/application-gateway/iis/install_nginx.sh"], "commandToExecute": "./install_nginx.sh" }'
done
#

Again though, before we paste it into the Cloud Shell, let's take a look at it line by line.

You must be getting familiar with this step now. Line 1 will return a list of resource groups that we have access to and assign that resource group name to our rgName variable.

rgName=$(az group list --query '[].{name:name}' --output tsv)

The rest of the code is a for loop that will be running against each of the scale sets. Line 3 starts the loop. Line 4 is the az vmss extension set command, which installs the custom script for Linux Azure extension on each virtual machine in our scale set.

for i in `seq 1 3`; do
 az vmss extension set 

Lines 5, 6, and 7 have flags that describe the extension in greater detail.

   --publisher Microsoft.Azure.Extensions 
   --version 2.0 
   --name CustomScript 

Line 8 references our resource group that we set in Line 1.

   --resource-group $rgName 

Line 9 references the scale set name we're running this against. This is a for loop, so we'll be running it against all three sets.

   --vmss-name myvmss$i 
   --settings '{ "fileUris":

Line 10 is a bit long. It's a command that downloads another script from a GitHub repository, then executes the script.

   ["https://raw.githubusercontent.com/linuxacademy/content-az-300-lab-repos/master/application-gateway/iis/install_nginx.sh"], "commandToExecute": "./install_nginx.sh" }'

Lines 11 and 12 are the end of our loop, then the hashtag that allows us to paste it all into Cloud Shell without having to hit Enter.

done
#

So, without further ado, let's paste the whole script into Cloud Shell and execute it.

This step won't take very long.

Test the Azure Application Gateway

Now that we've got this all set up, we need to test and make sure that everything is up and running. How do we test though? How do we make sure that our different URL traffic is going to the appropriate scale set? Well, we'll use a web browser and point to the Application Gateway's public IP address.

Close the Cloud Shell terminal, and we'll open up the public IP (pip-xxx) from the All Resources page. Look for the actual IP address, and copy it. Open up another web browser tab, and paste that IP address into the address bar.

We should land on a page with a hostname. Remember, we only stuck some very basic HTML into this configuration. But it's enough to demonstrate, as we browse through, that we are in fact browsing between virtual machines in a virtual machine scale set, as well as between the scale sets themselves.

Look close at the hostname though. If we hit refresh, we'll see it change slightly, by the last number. If we keep hitting the refresh button, we'll see that we keep cycling between the two hostnames. What we're doing is getting bounced back and forth between the two virtual hosts in the scale set that hosts index.html.

Now, let's browse to the images subdirectory. We'll find that at http://< OUR PUBLIC IP >:8080/images/test.html. We'll land at a page displaying Images: followed by a hostname. Here again, if you hit the refresh button in your browser, everything will stay the same except maybe the last character. Keep hitting refresh to see it swap. We're switching back and forth between virtual machines in the images scale set now.

But wait, there's more! Let's try that whole thing again for our video scale set. Go to that same URL, but swap out the word images for video. Go to http://< OUR PUBLIC IP >:8080/video/test.html. We should see the same kind of information displayed, but instead of the text starting with Images: it will start with Video:. And hitting the browser's refresh button will keep flipping us back and forth between the two machines in that scale set.

We Made It!

All of this testing means our Application Gateway is properly directing traffic between virtual machines within whatever scale set we're testing.

This also means we're done here. We achieved all of the objectives, and tested that they're all working. Congratulations!