23
loading...
This website collects cookies to deliver better user experience
Tip: Azure Resource Manager is a service. There is an implied benefit of using Azure Resource Manager templates compared with a framework like Terraform. As we're working through a consistent management layer, we're able to leverage the fact that ARM is able to store the current state of our environment as well.
Therefore - unlike Terraform, we don't need to manage the state of our Infrastructure as Code deployments. The state is handled for us by Azure Resource Manager (as it's a service) and reduces the complexity of managing and Infrastructure as Code deployment.
Scenario: Consider that we're creating Azure infrastructure by using a PowerShell or Azure CLI script-based script. We may need to have a series of conditionals scattered throughout the script (e.g. If this resource already exists, do this, else do this...). With ARM templates, we define the desired state and can typically re-run the ARM template to ensure the resource configuration has not drifted away from the expected result.
template language
that layers on top of that. JSON is typically about representing data (like XML or similar), so it makes sense that we would 'represent' our deployment in a data format, so that we can achieve a desired-state deployment. ARM Templates achieve that goal, at the cost of an easy authoring/usability experience -Note: Visual Studio and Visual Studio Code tooling has kept getting better and better. But sometimes, getting started with ARM templates could be a challenge. This is where the Azure Quickstart Templates Gallery comes in. It makes it easier to get started quickly. These templates aren't necessarily production ready (so you'll need to tweak these to your specific scenario), but they give you a great starting point across hundreds (seriously!) of scenarios.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"aadClientId": {
"type": "string",
"metadata": {
"description": "Client ID of the AAD B2C Application linked to the API Auth"
}
},
"aadB2cIssuer": {
"type": "string",
"metadata": {
"description": "Link to the well known Open ID Configuration for the sign in policy."
}
},
"environmentName": {
"type": "string",
"allowedValues": [
"dev",
"test",
"qa",
"prod"
],
"defaultValue": "dev",
"metadata": {
"description": "Define which environment is being deployed, this will affect naming convention of all resources"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"servicePrincipalObjectId": {
"type": "string",
"metadata": {
"description": "Object ID (not application ID) of the Azure DevOps service principal to be granted access to the KeyVault."
}
},
"tenantId": {
"type": "string",
"metadata": {
"description": "GUID of the Azure AD Tenant associated with the Azure KeyVault"
}
},
"templateContainerUri": {
"type": "string",
"metadata": {
"description": "URI of the Blob Storage Container containing the ARM Template building blocks"
}
},
"templateContainerSasToken": {
"type": "string",
"metadata": {
"description": "The SAS token of the container containing the ARM Template building blocks"
}
}
},
"variables": {
"abbreviations": {
"northeurope": "neu",
"westeurope": "weu"
},
"coreGlobalCogSvcSearchName": "[concat(variables('coreGlobalNamePrefix'), 'search')]",
"coreGlobalResourceGroupName": "[concat(variables('coreGlobalNamePrefix'), 'rg')]",
"coreGlobalNamePrefix": "[concat(variables('organisationPrefix'), '-core-', parameters('environmentName'), '-')]",
"coreRegionalApimServiceName": "[concat(variables('coreRegionalNamePrefix'),'apim')]",
"coreRegionalAppinsightsName": "[concat(variables('coreRegionalNamePrefix'), 'ai')]",
"coreRegionalNamePrefix": "[concat(variables('organisationPrefix'), '-core-', parameters('environmentName'), '-', variables('abbreviations')[parameters('location')], '-')]",
"coreRegionalResourceGroupName": "[concat(variables('coreRegionalNamePrefix'), 'rg')]",
"serviceGlobalNamePrefix": "[concat(variables('organisationPrefix'),'-', variables('serviceName'), '-', parameters('environmentName'), '-')]",
"serviceGlobalResourceGroupName": "[concat(variables('serviceGlobalNamePrefix'), 'rg')]",
"serviceRegionalFunctionName": "[concat(variables('serviceRegionalNamePrefix'), 'func')]",
"serviceRegionalKeyvaultName": "[concat(variables('serviceRegionalNamePrefix'), 'kv')]",
"serviceRegionalNamePrefix": "[concat(variables('organisationPrefix'),'-', variables('serviceName'), '-', parameters('environmentName'),'-', variables('abbreviations')[parameters('location')], '-')]",
"serviceRegionalNamePrefixWithoutDashes": "[replace(variables('serviceRegionalNamePrefix'), '-', '')]",
"serviceResourceGroupName": "[concat(variables('serviceRegionalNamePrefix'), 'rg')]",
"organisationPrefix": "th",
"serviceName": "admin"
},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "functionDeployment",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateContainerUri'), 'function.json', parameters('templateContainerSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"aadClientId": {
"value": "[parameters('aadClientId')]"
},
"aadB2cIssuer": {
"value": "[parameters('aadB2cIssuer')]"
},
"namePrefix": {
"value": "[variables('serviceRegionalNamePrefix')]"
},
"namePrefixWithoutDashes": {
"value": "[variables('serviceRegionalNamePrefixWithoutDashes')]"
},
"appInsightsResourceGroup": {
"value": "[variables('coreRegionalResourceGroupName')]"
},
"appInsightsName": {
"value": "[variables('coreRegionalAppinsightsName')]"
},
"cogSvcResourceGroup": {
"value": "[variables('coreGlobalResourceGroupName')]"
},
"cogSvcAccountName": {
"value": "[variables('coreGlobalCogSvcSearchName')]"
}
}
},
"comments": "Downstream template to deploy an Azure Function (Function App, App Serivce Plan) and Storage Account, by using the Theatreers Azure Function Building Block."
},
{
"apiVersion": "2017-05-10",
"name": "[concat(variables('serviceRegionalFunctionName'), 'ServiceAPIsDeployment')]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[variables('coreRegionalResourceGroupName')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateContainerUri'), 'apim-apis.json', parameters('templateContainerSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apimServiceName": {
"value": "[variables('coreRegionalApimServiceName')]"
},
"functionName": {
"value": "[variables('serviceRegionalFunctionName')]"
},
"serviceName": {
"value": "[variables('serviceName')]"
}
}
},
"comments": "Downstream template to deploy an APIs for the given Microservice."
},
{
"apiVersion": "2017-05-10",
"name": "[concat(variables('serviceRegionalFunctionName'), 'BackendDeployment')]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[variables('coreRegionalResourceGroupName')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateContainerUri'), 'apim-backend.json', parameters('templateContainerSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"apimServiceName": {
"value": "[variables('coreRegionalApimServiceName')]"
},
"functionName": {
"value": "[variables('serviceRegionalFunctionName')]"
},
"functionResourceGroup": {
"value": "[variables('serviceResourceGroupName')]"
}
}
},
"comments": "Downstream template to deploy an APIs for the given Microservice."
},
{
"apiVersion": "2017-05-10",
"name": "keyVaultDeployment",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('templateContainerUri'), 'keyVault.json', parameters('templateContainerSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"vaultName": {
"value": "[variables('serviceRegionalKeyvaultName')]"
},
"tenantId": {
"value": "[parameters('tenantId')]"
},
"objectId": {
"value": "[parameters('servicePrincipalObjectId')]"
}
}
},
"comments": "Downstream template to deploy Azure KeyVault, associate it with a gievn tenant and assign a Service Principal Object with access to secrets. This uses the Theatreers Azure KeyVault Building Block."
}
],
"outputs": {}
}
Note: Here is the exact wording from the Project Bicep GitHub repository -
As of v0.3, Bicep is now supported by Microsoft Support Plans and Bicep has 100% parity with what can be accomplished with ARM Templates. As of this writing, there are no breaking changes currently planned, but it is still possible they will need to be made in the future.
az deployment group create -f {{templatefile}} -g {{resourcegroup}}
command. Rather than passing a reference to your ARM template (.json file), you pass in a reference to a Bicep Template (.bicep file).Tip: Hopefully by now you've noticed the play on words of ARM
(Azure Resource Manager) and Bicep
. That's where the name comes from :)
Thought: What about your existing ARM templates? I don't believe there's any transpiling functionality right now, so that you can easily move across from ARM Templates to Bicep. ARM Templates aren't going anywhere though! Here is some additional context from the team from the Project Bicep GitHub repository.
Note that while we want to make it easy to transition to Bicep, we will continue to support and enhance the underlying ARM Template JSON language. As mentioned in What is Bicep?, ARM Template JSON remains the wire format that will be sent to Azure to carry out a deployment.
Tip: You don't need to start from scratch either! The Azure Quickstart Templates Gallery is continuously growing, and doesn't just have ARM Templates (JSON), but also contains Bicep files as well. See an example here.
"parameters": {
"aadClientId": {
"type": "string",
"metadata": {
"description": "Client ID of the AAD B2C Application linked to the API Auth"
},
"defaultValue": "DefaultValue",
}
}
@description('Client ID of the AAD B2C Application linked to the API Auth')
param aadClientId string = 'DefaultValue'
"variables": {
"coreGlobalCogSvcSearchName": "[concat(variables('coreGlobalNamePrefix'), 'search')]"
}
var coreGlobalCogSvcSearchName = '${coreGlobalNamePrefix}search'
"resources": [
{
"apiVersion": "2017-05-10",
"name": "functionDeployment",
"type": "Microsoft.Resources/deployments",
...
},
resource functionDeployment 'Microsoft.Resources/deployments@2017-05-10' = {
...
}
@description('Client ID of the AAD B2C Application linked to the API Auth')
param aadClientId string
@description('Link to the well known Open ID Configuration for the sign in policy.')
param aadB2cIssuer string
@description('Define which environment is being deployed, this will affect naming convention of all resources')
@allowed([
'dev'
'test'
'qa'
'prod'
])
param environmentName string = 'dev'
@description('Location for all resources.')
param location string = resourceGroup().location
@description('Object ID (not application ID) of the Azure DevOps service principal to be granted access to the KeyVault.')
param servicePrincipalObjectId string
@description('GUID of the Azure AD Tenant associated with the Azure KeyVault')
param tenantId string
@description('URI of the Blob Storage Container containing the ARM Template building blocks')
param templateContainerUri string
@description('The SAS token of the container containing the ARM Template building blocks')
param templateContainerSasToken string
var abbreviations = {
northeurope: 'neu'
westeurope: 'weu'
}
var coreGlobalCogSvcSearchName = '${coreGlobalNamePrefix}search'
var coreGlobalResourceGroupName = '${coreGlobalNamePrefix}rg'
var coreGlobalNamePrefix = '${organisationPrefix}-core-${environmentName}-'
var coreRegionalApimServiceName = '${coreGlobalNamePrefix}apim'
var coreRegionalAppInsightsName = '${coreGlobalNamePrefix}ai'
var coreRegionalNamePrefix = '${organisationPrefix}-core-${environmentName}-${abbreviations[location]}-'
var coreRegionalResourceGroupName = '${coreRegionalNamePrefix}rg'
var serviceGlobalNamePrefix = '${organisationPrefix}-${serviceName}-${environmentName}-'
var serviceGlobalResourceGroupName = '${serviceGlobalNamePrefix}rg'
var serviceRegionalFunctionName = '${serviceGlobalNamePrefix}func'
var serviceRegionalKeyvaultName = '${serviceGlobalNamePrefix}kv'
var serviceRegionalNamePrefix = '${organisationPrefix}-${serviceName}'
var serviceRegionalNamePrefixWithoutDashes = replace(serviceRegionalNamePrefix, '-', '')
var serviceResourceGroupName ='${serviceRegionalNamePrefix}rg'
var organisationPrefix = 'th'
var serviceName = 'admin'
/ Downstream template to deploy an Azure Function (Function App, App Serivce Plan) and Storage Account,
/ by using the Theatreers Azure Function Building Block.
resource functionDeployment 'Microsoft.Resources/deployments@2017-05-10' = {
name: 'functionDeployment'
properties: {
mode: 'Incremental'
templateLink: {
uri: '${templateContainerUri}function.json${templateContainerSasToken}'
contentVersion: '1.0.0.0'
}
parameters: {
aadClientId: aadClientId
aadB2cIssuer: aadB2cIssuer
namePrefix: serviceRegionalNamePrefix
namePrefixWithoutDashes: serviceRegionalNamePrefixWithoutDashes
appInsightsResourceGroup: coreRegionalResourceGroupName
appInsightsName: coreRegionalAppInsightsName
cogSvcResourceGroup: coreGlobalResourceGroupName
cogSvcAccountName: coreGlobalCogSvcSearchName
}
}
}
/ Downstream template to deploy an APIs for the given Microservice.
resource serviceAPIsDeployment 'Microsoft.Resources/deployments@2017-05-10' = {
name: 'ServiceAPIsDeployment'
resourceGroup: coreRegionalResourceGroupName
properties: {
mode: 'Incremental'
templateLink: {
uri: '${templateContainerUri}apim-apis.json${templateContainerSasToken}'
contentVersion: '1.0.0.0'
}
parameters: {
apimServiceName: coreRegionalApimServiceName
functionName: serviceRegionalFunctionName
serviceName: serviceName
}
}
}
/ Downstream template to deploy an APIs for the given Microservice.
resource backendDeployment 'Microsoft.Resources/deployments@2017-05-10' = {
name: 'backendDeployment'
resourceGroup: coreRegionalResourceGroupName
properties: {
mode: 'Incremental'
templateLink: {
uri: '${templateContainerUri}apim-backend.json${templateContainerSasToken}'
contentVersion: '1.0.0.0'
}
parameters: {
apimServiceName: coreRegionalApimServiceName
functionName: serviceRegionalFunctionName
functionResourceGroup: serviceResourceGroupName
}
}
}
/ Downstream template to deploy Azure KeyVault, associate it with a gievn tenant and assign a Service Principal Object with access to secrets.
/ This uses the Theatreers Azure KeyVault Building Block.
resource keyVaultDeployment 'Microsoft.Resources/deployments@2017-05-10' = {
name: 'keyVaultDeployment'
properties: {
mode: 'Incremental'
templateLink: {
uri: '${templateContainerUri}keyVault.json${templateContainerSasToken}'
contentVersion: '1.0.0.0'
}
parameters: {
value: serviceRegionalKeyvaultName
tenantId: tenantId
objectId: servicePrincipalObjectId
}
}
}
serviceGlobalResourceGroupName
) - so could do some further optimisation of my template as well!