Microsoft Azure is Microsoft’s globally distributed cloud platform and provides over 200 products and services, covering all the service models previously discussed – from virtual machines to cognitive services. Managing all your services and subscriptions can be done through the Azure portal, which can be accessed via https://portal.azure.com. The portal isn’t the only option – Azure also offers a comprehensive API and CLI, both of which will be explored throughout this book. There is also a marketplace where Microsoft partners, independent software vendors (ISVs), and startups can offer their solutions and services that have been optimized to run on Azure.
Azure’s giant of an identity platform is known as Azure Active Directory (AAD), which will be referred to throughout this book many times. At no point will we be covering all aspects of AAD in depth – only the areas that are relevant to this exam. Subscriptions provide you with access to Azure products and services. Companies can have multiple subscriptions, allowing for a separation of billing and access control, as well as management groups that group together multiple subscriptions. Within those subscriptions, you can create your resources, grouped into resource groups (discussed shortly).
Regions and availability zones
When you create a resource in Azure, you often need to specify the region in which to create the resource. As potentially heartbreaking as “there is no cloud, it’s just someone else’s computer” might be, this phrase and others similar have become popular in recent years, and we covered the meaning behind it previously. With Azure consisting of a global network of data centers around the world, you have the flexibility to select the region in which the data center hardware that will host your service is located.
So, what is an Azure region? A region is a geographical area within which one or more (usually more) Azure data centers reside, connected through a dedicated regional low-latency network. With data centers being grouped within a latency-defined perimeter (of less than 2 milliseconds), Azure ensures that workloads are balanced between them appropriately. Note that some services are only available in certain Azure regions. Regions allow you to create your resources as close as possible to you or your users, as well as cater to data residency requirements you might have. There are special Azure regions that have been created for certain government bodies, keeping them isolated from the public infrastructure.
Availability zones consist of one or more physically separate data centers within the same Azure region, connected through high-speed fiber-optic networks, with independent power, cooling, and networking. If one availability zone goes down, the other continues to operate. There are a minimum of three zones within a single region. Depending on the region and service, you may be able to select whether your data is replicated across the same zone, other zones within the same region, or another region entirely. There is plenty of documentation available out there, should you wish to read more on this topic. For this recap, we have gone into enough detail for now.
When it comes to the deployment and management of Azure resources, a topic you must understand is Azure Resource Manager.
Azure Resource Manager
Before Azure Resource Manager (ARM) was introduced in 2014, resources were deployed and managed using Azure Service Manager (ASM). With ASM, all resources were deployed and managed individually – if you wanted to manage resources together according to your application life cycle, for example, you would need to create scripts to do so.
In 2014, Microsoft introduced ARM, adding the concept of a resource group. Resource groups are units of management for your logically related resources. With ARM, all resources must be a member of a resource group, and only one, although supported resources can be moved between resource groups.
Resource groups provide a logical grouping of resources, so you can organize resources that share the same life cycle into a resource group. When the time comes to remove said resources, you can remove the resource group, which will remove all those related resources. Resource groups can also be used as a scope for applying role-based access control (RBAC) – so accounts that need access to resources within a resource group can be provided with access at the resource group level, without needing permissions to all other resources/resource groups, or at a higher level, such as the subscription level.
One organizational concept I’ll mention here is tags. While resource groups are great for organizing and grouping resources, their organizational usefulness has limits, especially when a resource can only be a member of one resource group at a time. Tags can be added to resources for additional organization and categorization.
Tags work as name-value pairs and can be used however you see fit – perhaps for a cost center, an environment, department, classification, or any other purpose (see the Recommended content section of the Cloud Adoption Framework guide, which contains guides on tagging decisions). At the time of writing, supported resources can have as many as 50 tags, with tag names limited to 512 characters (storage account tag names are an exception, where the limit is 128 characters) and tag values limited to 256 characters.
Any request – be it from the Azure portal, Azure PowerShell, the Azure CLI, SDKs, or REST clients – is received by ARM, which will then authenticate and authorize the request before sending the request to the Azure service. All methods, including via the portal, make use of the same ARM REST APIs – you just can’t interact with the APIs directly. Some example services can be seen in the following diagram:
Figure 1.3 – Illustration of the role ARM plays in handling Azure requests
In addition to being able to manage, secure, and monitor resources as a group with resource groups, ARM also introduced Azure Resource Manager templates (ARM templates) – a JSON file that defines one or more resources as a declarative template. You define what resources you want to deploy and any dependencies, and ARM will handle the orchestration. ARM templates allow you to repeatedly and consistently deploy resources, defined in code – Azure’s native Infrastructure-as-Code (IaC) solution.
IaC will be explored in more depth later in this book; for now, just know that if your infrastructure is defined in code, you can programmatically deploy your infrastructure consistently and rapidly, reducing the risk of human error, as well as being able to remove resources from a resource group that haven’t been defined in an ARM template, should you wish. You can even take an existing resource or resource group and export them to an ARM template for future automation.
Another benefit of ARM is idempotence – by default, redeploying an ARM template to a resource group that already contains resources that match those in the ARM template won’t affect those resources. This means that you can deploy the ARM template to reduce environment drift, without risking impacting those resources that match the specification in the template. If resources are missing from the resource group that are present in the ARM template, those resources will be deployed, bringing the environment aligned with the desired setup.
ARM templates
We just touched on ARM templates being a great way of deploying resources in a consistent, repeatable way, using a declarative template. Here’s a very simple example of an ARM template, which I will use to deploy a storage account to my resource group:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"defaultValue": "stdemoaz204"
},
"purpose": {
"type": "string"
}
},
"resources": [{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"tags": {
"purpose": "[parameters('purpose')]"
},
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Premium_LRS",
"tier": "Premium"
}
}]
}
This template was created with relative ease using the Azure Resource Manager (ARM) Tools for Visual Studio Code extension for Visual Studio Code.
As you can see, the template specifies the schema and content version, followed by the storageAccountName
and purpose
parameters, the former having a default value set. The last part of the template specifies the resource I would like to deploy via this template. The name pulls the value from the storageAccountName
parameter. Skip down a few lines, and you can see I’m setting a tag on the resource called purpose
and that a value is getting pulled from the purpose
parameter. On the next line, we specify that the location (region) this resource will be created in is going to be the same one as the resource group where I will deploy this template. The last few lines are specific to storage accounts and specify the kind of storage account, tier, and replication settings (yes, I know we skipped type
and apiVersion
; bear with me).
With this file saved as deploy.json
(the name doesn’t matter, although the extension needs to be .json
), let’s look at the commands for creating the resource group and deploying the resource using the Az
PowerShell module (more on that shortly). The Azure CLI or portal could have also been used:
New-AzResourceGroup -Name "<group name>" -Location "<desired location>"
, substituting <group name>
with the desired name of the resource group, and <desired location>
with the relevant Azure region (which will also be used as the region for the storage account).
To avoid any confusion, my example verbatim is New-AzResourceGroup -Name "rg-az-204" -Location "uksouth"
.
- After receiving confirmation that the resource group was created, the
New-AzResourceGroupDeployment -Name "<deploymentName>" -ResourceGroupName "<group name>" -TemplateFile "<ARM template path>" -storageAccountName "<storage account name>" -purpose "<purpose tag value>"
command creates the deployment and specifies the parameters. Substitute <deploymentName>
with a deployment name without whitespaces (it’s a good idea to make this unique per resource group for accurate deployment monitoring), <group name>
with your resource group name, <ARM template path>
with the relevant path to your ARM template, <storage account name>
with the desired storage account name (numbers and lowercase letters only), and <purpose tag value>
with whatever purpose value you want for the tag. Strictly speaking, not all these need to be surrounded by quotes – it’s more of a habit. I’d rather use them and not need them than need them and not use them!
To avoid any confusion, my example verbatim is New-AzResourceGroupDeployment -Name "StorageDeployment_1" -ResourceGroupName "rg-az-204" -TemplateFile ".\ARM templates\deploy.json" -storageAccountName "strfirstarm" -purpose 'AZ-204 book"
.
Once completed, I could run the last command again the same as I did previously, but because the resource declared in the template already exists with the same configuration as in the template, the resource wouldn’t be touched. I could also just change the resource name and ARM would deploy another resource with a different name but with the same configuration – the beauty of IaC.
Although we’re discussing ARM templates as Microsoft’s first-party IaC solution, there are plenty of third-party solutions available that can also deploy and configure Azure resources. Microsoft also has another tool called Bicep that provides a more developer-friendly experience and greater functionality. At the time of writing, Bicep is not part of the exam, so we won’t go into further detail here. However, you can find a link to its documentation in the Further reading section.
Back to the template and the two properties we didn’t talk about – type and apiVersion – they both relate to resource providers and types. We’ll cover these in the next section.
Resource providers and resource types
Now that we have introduced ARM, it’s worthwhile going one level deeper and discussing Azure resource providers. ARM relies on a variety of resource providers to manage distinct types of resources. For example, when deploying a resource, the request will come to ARM, which will then use the appropriate resource provider for that resource type. Resource providers are identified by a resource provider namespace – some common examples of resource providers are Microsoft.Compute
, Microsoft.Storage
, and Microsoft.Web
. Each resource provider has one or more resource types. If we take the example of a virtual machine – ignoring all the additional resources that can be deployed alongside it for the moment (network resources, for example) – ARM will use the Microsoft.Compute/virtualMachines
resource type, which – as you can see – falls under the Microsoft.Compute
resource provider.
Why am I telling you this? For a couple of reasons:
- If you try to deploy a resource and the relevant resource provider hasn’t been registered within your subscription, you may not be able to deploy that resource, depending on the permissions for registering resource providers in the subscription.
- When you start looking at deployments via ARM templates or even within the Azure portal, you will see a reference to resource providers and resource types, so it makes sense to introduce them beforehand (look back at the previous ARM template and you will see).
Here’s an example deployment from the Azure portal. I deployed a virtual machine and the required additional resources. You can see the resource type (comprised of the resource provider namespace and resource type) in the Type column:
Figure 1.4 – Resource providers and resource types in the Azure portal
Resource providers provide extensibility, allowing new resource providers to be added in a consistent way when new services are added to Azure. You can also write a resource provider for managing custom resource types. The availability of resource providers and resource types (and specific API versions) vary, depending on the Azure region. There is also a tool within the Azure portal called Resource Explorer that allows you to explore the various resource providers and types that are available. Every resource type will have one or more API versions available. More on that later.
Resource definitions
One last topic before we move on is resource definitions. Although certain properties will be present in some resources and not others, all resources managed by ARM have the following properties in their definition:
Name
ResourceGroupName
ResourceType
Location
ResourceId
Tags
(optional)
It’s useful to become familiar with what a typical resource definition looks like as you will likely encounter them often, in various forms. Most of these have been discussed already (location is the same as a region in this context), except for ResourceId
. Resource IDs are globally unique identifiers for a specific resource, in the /subscription/<subscription ID>/resourceGroups/<resource group name>/providers/<resource provider>/<resource type>/<resource name>
format. Here is an example of a virtual machine with a single tag name and value:
Figure 1.5 – Example resource definition including a tag
How did I get that information? Using Azure PowerShell. In the next section, we’ll look at how to use the Azure CLI and Azure PowerShell.
Azure CLI and Azure PowerShell
As this chapter is intended to be a recap, we won’t be going into too much depth here. If you have installed the Az PowerShell module and haven’t already signed in with it, you can use the Connect-AzAccount
cmdlet. If you have installed the Azure CLI and haven’t already signed in with it, you can use the az login
command. For this chapter, I will be using Azure Cloud Shell from within my browser. If you would like to do the same, you can find instructions here: https://docs.microsoft.com/azure/cloud-shell/overview. Let’s explore a few basic commands that touch on some of the topics we’ve discussed so far. We will go through examples for both PowerShell and the Azure CLI.
Az PowerShell module
Here are a few basic commands you can run within your PowerShell session (whether locally or via the PowerShell Azure Cloud Shell):
- List all Azure locations available to your current subscription with
Get-AzLocation
. Notice that Location
is slightly different from DisplayName
.
- List the resource providers available to your current subscription with
Get-AzLocation | Select -ExpandProperty Providers | sort
.
- List some of the locations in which the
Microsoft.Compute/virtualMachines
resource type is available and which API versions are available with (Get-AzResourceProvider -ProviderNamespace Microsoft.Compute).ResourceTypes | where ResourceTypeName -eq "virtualMachines"
.
- If you already have a resource deployed, you can list the resource details as in my previous PowerShell screenshot with
Get-AzResource | Where Name -eq "<resource name>"
, substituting <resource name>
with the name of your resource.
Azure CLI
Here are a few basic commands you can run within your CLI session (whether locally or via the Bash Azure Cloud Shell):
- List all Azure locations available to your current subscription with
az account list-locations
. Notice that although you can immediately see additional information, displayName
and name
are reflective of what we saw with PowerShell. To filter out the noise and just list the names, use az account list-locations --query [].name -o tsv
.
- List the resource providers available to your current subscription with
az provider list --query [].namespace -o tsv
.
- List the locations in which the
Microsoft.Compute/virtualMachines
resource type are available and which API versions are available with az provider show --namespace Microsoft.Compute --query "resourceTypes[?resourceType == 'virtualMachines'].{Locations:locations[], apiVersions:apiVersions[]}"
.
- If you already have a resource deployed, you can list the resource details with
az resource list --name "<resource name>"
, substituting <resource name>
with the name of your resource.
These were just a few basic examples of using the Az
PowerShell module and the Azure CLI to get information from Azure. There will be many examples throughout this book, so having an introduction to them early on – if you weren’t already familiar with them – can be beneficial.