ARM Lab 102 MS

After following ARM Template 101 and AZ-104-MS Azure Administrator 101 quick ref

We are ready for some labs, all labs has a template and a parameters file

Remember also the quick starts

https://azure.microsoft.com/en-us/resources/templates/

Any way we will start at 0, many of the parameters may change but we need to look at prices first, since we we deploy and destroy over and over again. The goal is just to learn IAC/ ARM and not spend money….

So lets recap bit and think about this!

If we look back at the free services the cost/ configuration for (is free for 12m) B1s is:

Ubuntu

Basic:

  • Resource group boose-rg
  • Region West Europe
  • Availability options Availability zone
  • Availability zone 1
  • Image Ubuntu Server 18.04 LTS – Gen1
  • Size Standard B1s (1 vcpu, 1 GiB memory)

Disks

  • OS disk type Standard HDD 32gib

Azure calculator

Pricing Calculator | Microsoft Azure

Lets look at some prices for virtual machines and storage accounts

Virtual machines

If we select region WE, OS Linux, type Ubuntu, Tier, Disk?

There is an option with TIER and Disk

  • Low priority, is the cheapest, you get just unused capacity
  • Basic, for development testing (but no LB or auto scale and slow IOPS)
  • Standard, default, better CPU/Higher max disk IOPS

The price heavily depends on region and offers available in that region, it is a jungle for now. If we use the above input and check availability in tiers, the SKU (stock keeping unit) instance and disk changes a lot.

Tier

  • Basic, development or testing or small scale
  • General purpose, Most business workloads, web/mobile apps/enterprise apps
  • Memory optimized, High performance db workloads in memory, real time data high per. transaction

So in order to create the “free” BS1 1 vCPU, 1 GB RAM, 4 GB Temp storage we need to set the following

  • Region West Europe
  • OS Linux
  • Type Ubuntu
  • Tier Standard
  • Instance BS1 1 vCPU, 1 GB RAM, 4 GB Temp storage NOK 0.0974/hour
  • VM’s = 1 x 730 (hours running)
  • Managed disk
  • Tier Standard HDD
  • Disk size 1 x S4: 32GiB, NOK 12.463/month
  • Storage transaction 100 x NOK 0.0041

Gives the total price of NOK 83.95 monthly cost if it runs for 730 hh.

Gives the total price of NOK 15.21 monthly cost if it runs for 24 hh.

Windows VM

If we swap the OS to Windows but keep the same settings but add:

  • OS Windows License included

Gives the total price of NOK 107.64 monthly cost if it runs for 730 hh.

Gives the total price of 15.98 monthly cost if it runs for 24 hh

Storage Account

  • Region WE
  • Redundancy LRS
  • Type Block Blob Storage
  • Access Tier Hot
  • Performance tier Standard
  • Storage Account Type General Purpose V2
  • Capacity 250 GB
  • […] Default write operations:
  • 100000 x NOK 0.438, Per 10,000 operations
  • List and create operations 100000 x NOK 0.438, Per 10,000 operations
  • Read operations 100000 x NOK 0.035, Per 10,000 operations
  • All other operations 1 x NOK 0.035, Per 10,000 operations
  • Data retrieval + write = 1000gb NOK 0.000 per GB

Gives the total price of NOK 48.87 monthly cost

Ok now we are ready

https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-tutorial-create-first-template?tabs=azure-powershell

1 Create and deploy your first ARM template

Install Azure Power shell module (as admin if all users need it)

As built, it takes some minutes, when it is done, type New-Az something to see if the cmd appear.

To start working with Azure PowerShell/Azure CLI, sign in with your Azure credentials.
Connect-AzAccount
If you have multiple Azure subscriptions, select the subscription you want to use:
Set-AzContext [SubscriptionID/SubscriptionName]

Your account, subscription name , tenant id and environment will be listed

Now lets create a rg, deploy template and verify it, then clean up

All code is stored here

https://github.com/spawnmarvel/powershell-cmd-bash/tree/master/arm

# New rg
New-AzResourceGroup -Name boose-rg -Location "West Europe"
# Deploy template
$templateFile = "C:\giti\powershell-cmd-bash\arm\beginners_template\azuredeploy.json"
New-AzResourceGroupDeployment -Name blanktemplate -ResourceGroupName boose-rg -TemplateFile $templateFile

# clean it
Get-AzResourceGroup -Name ‘boose*’ | Remove-AzResourceGroup -Force -AsJob

Check if succeeded, default is incremental

Verify in portal, in the rg check deployments to the right and press it, to get the history.

Now we are removing it, this can take some time….

2 Add a resource to your ARM template

We updated the json with the following to create a storage account, then we deployed the script with a new rg and a new template again

"resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "boosestorage",
      "location": "westeurope",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    }
  ]

Verify it in portal

Files for now

3 Add parameters to your ARM template

So lets add a parameters and make the template reusable and use not the hard coded boosestorage name

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "boosestorage",
      "location": "westeurope",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    }
  ]
}

With parameter

[...]
"contentVersion": "1.0.0.0",
  "parameters": {
    "storageName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 24
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "[parameters('storageName')]",
[...]

Lets deploy it (“If the resource already exists and no change is detected in the properties, no action is taken. If the resource already exists and a property has changed, the resource is updated. If the resource doesn’t exist, it’s created.“)

And the the storage account

Parameters enable you to customize the deployment by providing values that are tailored for a particular environment

The template always deploys a Standard_LRS storage account, you could use a parameter and a default value for adding different SKU’s.

[...]
 "storageSKU": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Standard_ZRS",
        "Premium_LRS",
        "Premium_ZRS",
        "Standard_GZRS",
        "Standard_RAGZRS"
      ]
    }
  },
[..]
"sku": {
        "name": "[parameters('storageSKU')]"
      },

If we now run Test-AzResourceGroupDeployment, we can test with a storage name and without and also with a change in the storage account to one of the allowed values for SKU.

Here we see that the name provide is taken, so we must supply a new one and test again, until it works.

Ok lets check it before we deploy it, it is Locally-redundant storage (LRS) now. Lets redeploy and change the SKU.

$resourceGr = "boose-rg"
# New rg
New-AzResourceGroup -Name $resourceGr -Location "West Europe"
# Deploy template
$templateFile = "C:\giti\powershell-cmd-bash\arm\beginners_template\azuredeploy.json"
New-AzResourceGroupDeployment -Name addName -ResourceGroupName $resourceGr -TemplateFile $templateFile -storageName "boosestorage1" -storageSKU Standard_GRS

It is now GRS

lets swap it back with a redeploy and yea!

If you add the ARM tools on VSC you get a good tool, with highlights and more

4 Add template functions

Dynamically construct values, system-provided func and USD func.
From the previous JSON file the locations was hard coded.

If we were to change this we could create parameter for the location, but there is also a another option.
Now we will use a GET func of the location of the rg

"location": "westeurope" # this is not good for flexibility.

[...] # to this->
"location": {
      "type": "string",
      "defaultValue":"[resourceGroup().location]"
    }

[...]
 "location": "[parameters('location')]",

Now we will use the location of of the rg to deploy the storage.

We now have boose-rg1 in east us, lets deploy

$resourceGr1 = "boose-rg1"
# add template functions
New-AzResourceGroupDeployment -Name DeployToRgZone2 -ResourceGroupName $resourceGr1 -TemplateFile $templateFile -storageName "boosestorage2" -storageSKU Standard_LRS

Lets check the deploy and then move it back to the main rg

And the storage is now in the rg location

And move it back to boose-rg in west europe

# https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/move-resource-group-and-subscription

$resourceNew = "boose-rg"
$resourceOld = "boose-rg1"
$storageToMove = Get-AzResource -ResourceGroupName $resourceOld -ResourceName "boosestorage2"

Write-Host $storageToMove.ResourceName+ " " + $storageToMove.Sku.Name
# our plan
$plan = Get-AzResource -ResourceGroupName $resourceOld -ResourceName "boosestorage2"
# execute the move
$result = Move-AzResource -DestinationResourceGroupName $resourceNew -ResourceId $plan.ResourceId
Write-Host $result

Move yes

And we are done with the moving

5 Add variables

Enabling you to write an expression once and reuse it throughout the template
Tired of guessing a unique name for the storage account name?

# New template
"parameters": {
    "storagePrefix": {
      "type": "string",
      "minLength": 3,
      "maxLength": 11
    },
    "storageSKU": {


[...]
"variables": {
    "uniqueStorageName": "[concat(parameters('storagePrefix'), uniqueString(resourceGroup().id))]"
  },

"apiVersion": "2019-04-01",
      "name": "[variables('uniqueStorageName')]",


# Vs old

"parameters": {
    "storageName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 30
    },
    "storageSKU": {


[...]
 "apiVersion": "2019-04-01",
 "name": "[parameters('storageName')]",

The uniqueString function creates a 13 character hash value, return val is built with the parameters.
Here we use the resource group ID as the input for the hash value.
So we can deploy to a different rg and get a unique name, if we deploy to the same rg, we get the same name.
Our storage name is now set to a variable and not a parameter.

Verbose switch to get information about the resources or Debug to get more information.

Here we are using the debug (we can continue one, all, H (stop) , S (pause pip, type exit to resume it, ? (is what we just said)

New-AzResourceGroupDeployment -Name addnameVariable -ResourceGroupName $resourceGr -TemplateFile $templateFile -storagePrefix "boose" -storageSKU Standard_LRS -Debug

Some flashes on progress, then done

Lets check it, and there it is.

Lets clean it and test with Verbose (we just get more information and the deploy continues)

Lets remove just the resource and not the rg, check for the cmd in language reference

Side note, typical properties for a resource is:

Get what we have now

6 Add outputs

We have just deployed some storage account without returning any information.
Lets do return some output.
Important:
Return value is obj (JSON), and the reference func to get runtime state of the storage account.
Get runtime, pass the name/ID of resource, here it is the same var as for creating the name of the stor.acc.
It returns the endpoint

Add the , “output” section to the template

[...]

   "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference(variables('uniqueStorageName')).primaryEndpoints]"
    }
  }
}

Now run the same deploy cmd as the last time, and you get a similar output

Outputs                 :
                          Name               Type                       Value
                          =================  =========================  ==========
                          storageEndpoint    Object                     {
                            "dfs": "https://boosec4ybsmchbhppi.dfs.core.windows.net/",
                            "web": "https://boosec4ybsmchbhppi.z6.web.core.windows.net/",
                            "blob": "https://boosec4ybsmchbhppi.blob.core.windows.net/",
                            "queue": "https://boosec4ybsmchbhppi.queue.core.windows.net/",
                            "table": "https://boosec4ybsmchbhppi.table.core.windows.net/",
                            "file": "https://boosec4ybsmchbhppi.file.core.windows.net/"
                          }

7 Use exported templates

Here the focus is to export templates and customize it.

The template we ended with is ok for stor.acc, but we could add or in the future you need more resources in the template.

Here is how to export and get the JSON.

Lets follow the tutorial and create:

In App Service (Web Apps, API Apps, or Mobile Apps), an app always runs in an App Service plan.
Azure Functions also has the option of running in an App Service plan. An App Service plan defines a set of compute resources for a web app to run. These compute resources are analogous to the server farm in conventional web hosting.
ref
https://docs.microsoft.com/en-us/azure/app-service/overview-hosting-plans

After it is created go the resource and export template. You can use this function to quickly export the base of a template, the parameters is just to change. Here the SKU has five parameters, all those are not necessary. Name is sufficient, but the planing is key to know what you want.

Now you have most of the JSON, so it is time to change it.
The changes we will do is:
Name to match our, use location parameter for app and remove some props.

Just for the fun of it we will the type in all, learning is doing.

This is a valid empty template, we will start with that and do the hard work…yea.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters":{},
  "variables":{},
  "resources": [],
  "outputs":{}
}

Using the extension it it giving hints to you, when you are getting into the syntax..

Parameters not used yet.

Ok, when do run first with -WhatIf, then -Debug to check if the template is valid before typing 5*yes to deply

So now we deployed a stor.acc (with prefix) and App service plan.

For : 8 Use quick start template, 9 Add tags, 10 Use parameter file go to ARM Lab 103

Scroll to Top