Tag Archives: Terraform

Terraform – Autoscale an App Service

I’ve recently been writing about Terraform – mainly because I’m learning it from scratch, and playing about with tech and then writing about it is basically my way of learning.

In this post, I’m going to build on this previous post on creating an App Service, by adding a Scale Out feature to it.

This is the App Service that we created in the referenced post:

In the image, you’ll see Scale Out. Note that it says (App Service Plan): in fact, this is just a link to the App Service Plan Scale Out. We can access it from here – let’s see what that looks like:

As we can see, there’s a single instance of the App Service, and it’s managed manually. What we’re going to do is change that so that the App Service is auto-scaled.

The Terraform script here is broadly taken from the example here. However, that applies to a VM Scale Set, whereas we’re applying it to an App Service Plan.

resource "azurerm_monitor_autoscale_setting" "example" {
  name                = "myAutoscaleSetting"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  target_resource_id  = azurerm_app_service_plan.app-service-plan.id
  profile {
    name = "default"
    capacity {
      default = 1
      minimum = 1
      maximum = 10
    }
    rule {
      metric_trigger {
        metric_name        = "CpuPercentage"
        metric_resource_id = azurerm_app_service_plan.app-service-plan.id
        time_grain         = "PT1M"
        statistic          = "Average"
        time_window        = "PT5M"
        time_aggregation   = "Average"
        operator           = "GreaterThan"
        threshold          = 90
      }
      scale_action {
        direction = "Increase"
        type      = "ChangeCount"
        value     = "1"
        cooldown  = "PT1M"
      }
    }
    rule {
      metric_trigger {
        metric_name        = "CpuPercentage"
        metric_resource_id = azurerm_app_service_plan.app-service-plan.id
        time_grain         = "PT1M"
        statistic          = "Average"
        time_window        = "PT5M"
        time_aggregation   = "Average"
        operator           = "LessThan"
        threshold          = 10
      }
      scale_action {
        direction = "Decrease"
        type      = "ChangeCount"
        value     = "1"
        cooldown  = "PT1M"
      }
    }
  }  
}

Some key points:

– The example uses “Percentage CPU”, whereas for an App Service, this gets switched to CpuPercentage.
– The resource IDs that are referred to are that of the App Service Plan.

Finally, if we apply that, we can see the autoscale:

References

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_autoscale_setting

https://stackoverflow.com/questions/58657096/error-creating-auto-scaling-rule-for-app-service-using-terraform-in-azure

Terraform – Provisioning an Azure App Service

In my previous post on Getting started with Terraform I covered a very quick, and vague explanation of what Terraform is, and what it does. In this post, I’m going to cover the explanation of what the various syntax looks like; I’m also going to provision some infrastructure in the form of an App Service.

Before we get into the what we’ll need to create an app service, let’s first analyse the config that we used in the previous post:

# Configure the Azure provider
terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = ">= 2.26"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "ukwest"
}

Let’s breakdown exactly what we’re seeing here for the resource:

Now that we’ve broken that down, it makes sense that, if we want to deploy an App Service, that we simply need to know what the correct type of the app service is. There’s probably a list of these somewhere.

Let’s have a look at the config for the App Service:

# App Service
resource "azurerm_app_service_plan" "app-service-plan" {
  name                = "pcm-app-service-plan"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}
resource "azurerm_app_service" "app-service" {
  name                = "pcm-app-service"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  app_service_plan_id = azurerm_app_service_plan.app-service-plan.id
}

Again, let’s break this down – starting with the plan:

Finally, let’s have a look at the app service itself – there’s not too much difference here:

If we now run

terraform.exe plan

Then we’ll see that it intends to create an app service plan and app service within that plan; running:

terraform.exe apply

Will execute that and generate our new resources.

Terraform – Getting Started

In this post, I’m going to download Terraform and create a resource group, and then change the location of that resource group. Most of what is in this post is much more succinctly put in the link to the Terraform tutorial at the end. Feel free to jump to the end and go there (I won’t be offended).

Download

Terraform is an application that runs locally, however, the install procedure is essentially just download an exe and place it in a directory. The download link is here. For my test, I downloaded the 64 bit Windows exe, and just extracted it to c:\tmp.

If you now run the Windows Terminal, you can run the terraform.exe and you’ll see a list of possible commands:

Since this is just an experiment, I won’t edit the path (perhaps we’ll come back to that in a later post), but if you are installing this, then it makes sense to have it in your Windows PATH – that way you can run it from anywhere.

To set-up terraform, the first step is to run:

.\terraform.exe init

If you do that now, you’ll get an error:

The directory has no Terraform configuration files. You may begin working
with Terraform immediately by creating Terraform configuration files.

Configuration Files

Configuration files essentially tell Terraform what you want it to do. At a very basic level, they have two sections:

Provider Block – where are we creating infrastructure

Resource Block – what are we creating

There are other features and sections, but getting down to basics, we need to say what we are creating, and where to create it.

The sample configuration from the tutorial referenced at the bottom of this post is this:

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = ">= 2.26"
    }
  }
}

# Provider - creating Infrastructure in Azure
provider "azurerm" {
  features {}
}

# Resource - creating a resource group
resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "westus2"
}

Now that we’ve created that, we can run init again; this time, it should work:

.\terraform.exe init

Plan

Let’s run this. Step one is to log-in to Azure – to do this, you’ll need the Azure CLI:

az login

Once you’re logged in to Azure, create the terraform plan:

.\terraform.exe plan

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

+ resource “azurerm_resource_group” “rg” {
+ id = (known after apply)
+ location = “westus2”
+ name = “myTFResourceGroup”
}

Plan: 1 to add, 0 to change, 0 to destroy.

That all looks good – so let’s apply that:

.\terraform.exe apply

This takes the plan, and executes it. Checking in the Azure Portal, I can see that I now have a resource group called myTFResourceGroup:

Okay, so this is where the tutorial took me to.

Change of Plan

I happen to live in the UK; so the first thing I want to try is to change the location. I actually thought that terraform would balk at this; but no. Here’s the modified .tf file:

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = ">= 2.26"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "ukwest"
}

When I run this, it actually comes up with a way to get from where it is to where I want it to be:

PS C:\tmp> .\terraform.exe plan
azurerm_resource_group.rg: Refreshing state… [id=/subscriptions/16a7fc79-9bea-4d04-83a1-09f3b260adb0/resourceGroups/myTFResourceGroup]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

# azurerm_resource_group.rg must be replaced
-/+ resource “azurerm_resource_group” “rg” {
~ id = “/subscriptions/16a7fc79-9bea-4d04-83a1-09f3b260adb0/resourceGroups/myTFResourceGroup” -> (known after apply)
~ location = “westus2” -> “ukwest” # forces replacement
name = “myTFResourceGroup”
– tags = {} -> null
}

Plan: 1 to add, 0 to change, 1 to destroy.

Okay, so what it’s telling me is that it’s going to trash my resource group, and recreate it in the correct location. That seems fine, so I’ll apply that change.

Pulling The Rug

Next, I wanted to see what would happen if I just removed the resource group from the portal. My guess was that Terraform should realise what happened and simply recreate it.

And, sure enough, that’s exactly what it did:

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# azurerm_resource_group.rg will be created
+ resource “azurerm_resource_group” “rg” {
+ id = (known after apply)
+ location = “ukwest”
+ name = “myTFResourceGroup”
}

Plan: 1 to add, 0 to change, 0 to destroy.

References

https://learn.hashicorp.com/tutorials/terraform/azure-build?in=terraform/azure-get-started