AZ-104 Objective 3.1: Automate Deployment of Resources by Using ARM Templates or Bicep Files
AZ-104 Exam Focus: This objective covers Infrastructure as Code (IaC) using Azure Resource Manager (ARM) templates and Bicep files. Understanding template structure, deployment automation, and resource management is crucial for Azure administrators. Master these concepts for both exam success and real-world Azure infrastructure automation.
Understanding Infrastructure as Code (IaC)
Infrastructure as Code (IaC) is the practice of managing and provisioning infrastructure through machine-readable definition files, rather than through physical hardware configuration or interactive configuration tools. Azure provides ARM templates and Bicep files as declarative IaC solutions. This approach works hand-in-hand with Azure governance policies to ensure your infrastructure deployments comply with organizational standards.
IaC Benefits:
- Consistency: Repeatable and consistent deployments
- Version Control: Track infrastructure changes over time
- Automation: Automated deployment and management
- Collaboration: Team-based infrastructure development
- Disaster Recovery: Quick infrastructure recreation
- Compliance: Standardized and auditable infrastructure
Understanding ARM Templates and Bicep
Azure Resource Manager (ARM) Templates
ARM templates are JSON files that define the infrastructure and configuration for your Azure solution. They use declarative syntax, which means you describe what you want to deploy without writing the sequence of programming commands to create it.
ARM Template Structure
Template Components:
- $schema: JSON schema file that describes the version of the template language
- contentVersion: Version of the template (such as 1.0.0.0)
- parameters: Values that are provided when deployment is executed
- variables: Values that are used as JSON fragments in the template
- functions: User-defined functions that are available within the template
- resources: Resources that are deployed or updated
- outputs: Values that are returned after deployment
Bicep Files
Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources. It provides a more concise syntax compared to ARM templates while maintaining the same capabilities.
Bicep Advantages
Key Benefits:
- Simplified Syntax: More readable and concise than JSON
- Type Safety: Built-in type checking and validation
- IntelliSense: Better IDE support and autocomplete
- Modularity: Easy to break into modules and reuse
- Compilation: Compiles to ARM templates automatically
- No State Management: No need to manage state files
Interpret an Azure Resource Manager Template or a Bicep File
ARM Template Example
Basic ARM Template Structure:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "defaultValue": "mystorageaccount", "metadata": { "description": "Name of the storage account" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Location for all resources" } } }, "variables": { "storageAccountName": "[concat(parameters('storageAccountName'), uniqueString(resourceGroup().id))]" }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-09-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2", "properties": { "accessTier": "Hot" } } ], "outputs": { "storageAccountName": { "type": "string", "value": "[variables('storageAccountName')]" } } }
Bicep File Example
Equivalent Bicep File:
@description('Name of the storage account') @minLength(3) @maxLength(24) param storageAccountName string = 'mystorageaccount' @description('Location for all resources') param location string = resourceGroup().location var uniqueStorageAccountName = '${storageAccountName}${uniqueString(resourceGroup().id)}' resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: uniqueStorageAccountName location: location sku: { name: 'Standard_LRS' } kind: 'StorageV2' properties: { accessTier: 'Hot' } } output storageAccountName string = storageAccount.name
Template Interpretation
Key Elements to Understand
Template Analysis:
- Schema and Version: Template language version and compatibility
- Parameters: Input values that can be customized during deployment
- Variables: Computed values used throughout the template
- Resources: Azure resources being deployed with their properties
- Dependencies: Resource dependencies and deployment order
- Outputs: Values returned after successful deployment
Modify an Existing Azure Resource Manager Template
Common Template Modifications
Modifying ARM templates involves understanding the existing structure and making targeted changes to parameters, resources, or configuration.
Adding Parameters
Parameter Addition Example:
// Add new parameter to existing template "parameters": { "storageAccountName": { "type": "string", "defaultValue": "mystorageaccount" }, "storageAccountType": { "type": "string", "defaultValue": "Standard_LRS", "allowedValues": [ "Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Premium_LRS" ], "metadata": { "description": "Storage account type" } }, "environment": { "type": "string", "defaultValue": "dev", "allowedValues": [ "dev", "test", "prod" ], "metadata": { "description": "Environment name" } } }
Modifying Resources
Resource Modification Example:
// Modify existing storage account resource { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-09-01", "name": "[variables('storageAccountName')]", "location": "[parameters('location')]", "sku": { "name": "[parameters('storageAccountType')]" }, "kind": "StorageV2", "properties": { "accessTier": "Hot", "allowBlobPublicAccess": false, "networkAcls": { "defaultAction": "Deny", "bypass": "AzureServices" } }, "tags": { "Environment": "[parameters('environment')]", "Project": "MyProject" } }
Adding New Resources
Adding Virtual Network Resource:
// Add virtual network to existing template { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2021-05-01", "name": "[variables('virtualNetworkName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('vnetAddressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetAddressPrefix')]" } } ] }, "dependsOn": [] }
Modify an Existing Bicep File
Bicep File Modifications
Bicep files are easier to modify due to their simplified syntax and better readability. Common modifications include adding parameters, resources, and improving modularity.
Adding Parameters in Bicep
Parameter Addition Example:
@description('Name of the storage account') @minLength(3) @maxLength(24) param storageAccountName string = 'mystorageaccount' @description('Storage account type') @allowed([ 'Standard_LRS' 'Standard_GRS' 'Standard_RAGRS' 'Premium_LRS' ]) param storageAccountType string = 'Standard_LRS' @description('Environment name') @allowed([ 'dev' 'test' 'prod' ]) param environment string = 'dev' @description('Location for all resources') param location string = resourceGroup().location
Modifying Resources in Bicep
Resource Modification Example:
var uniqueStorageAccountName = '${storageAccountName}${uniqueString(resourceGroup().id)}' resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: uniqueStorageAccountName location: location sku: { name: storageAccountType } kind: 'StorageV2' properties: { accessTier: 'Hot' allowBlobPublicAccess: false networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' } } tags: { Environment: environment Project: 'MyProject' } }
Adding Modules in Bicep
Module Usage Example:
// Create a module for virtual network module vnetModule 'modules/vnet.bicep' = { name: 'vnet-${environment}' params: { vnetName: 'vnet-${environment}' location: location addressPrefix: '10.0.0.0/16' subnetName: 'subnet-${environment}' subnetAddressPrefix: '10.0.1.0/24' } } // Reference module outputs output vnetId string = vnetModule.outputs.vnetId output subnetId string = vnetModule.outputs.subnetId
Deploy Resources by Using an ARM Template or Bicep File
Deployment Methods
Azure provides multiple methods for deploying ARM templates and Bicep files, each with different use cases and capabilities.
Azure Portal Deployment
Portal Deployment Process:
- Navigate to Deploy: Go to Azure Portal → "Deploy a custom template"
- Select Template: Choose "Build your own template in the editor"
- Upload Template: Paste template JSON or upload file
- Configure Parameters: Set parameter values
- Review and Deploy: Review settings and deploy
PowerShell Deployment
PowerShell Deployment Commands:
# Deploy ARM template New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.json" -TemplateParameterFile "parameters.json" # Deploy with inline parameters New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.json" -storageAccountName "mystorageaccount" -location "East US" # Deploy with parameter object $parameters = @{ storageAccountName = "mystorageaccount" location = "East US" environment = "prod" } New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.json" -TemplateParameterObject $parameters # Deploy Bicep file New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.bicep" -TemplateParameterFile "parameters.json" # Deploy with What-If preview New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.json" -WhatIf # Deploy with validation only New-AzResourceGroupDeployment -ResourceGroupName "MyRG" -TemplateFile "template.json" -ValidateOnly
Azure CLI Deployment
Azure CLI Deployment Commands:
# Deploy ARM template az deployment group create --resource-group MyRG --template-file template.json --parameters @parameters.json # Deploy with inline parameters az deployment group create --resource-group MyRG --template-file template.json --parameters storageAccountName=mystorageaccount location="East US" # Deploy Bicep file az deployment group create --resource-group MyRG --template-file template.bicep --parameters @parameters.json # Deploy with What-If preview az deployment group create --resource-group MyRG --template-file template.json --what-if # Deploy with validation only az deployment group validate --resource-group MyRG --template-file template.json --parameters @parameters.json # Deploy to subscription level az deployment sub create --location "East US" --template-file template.json --parameters @parameters.json # Deploy to management group level az deployment mg create --location "East US" --template-file template.json --parameters @parameters.json
Deployment Best Practices
✅ Deployment Recommendations:
- Use What-If: Always preview changes before deployment
- Validate Templates: Validate templates before deployment
- Incremental Deployments: Use incremental deployment mode
- Parameter Files: Use separate parameter files for different environments
- Version Control: Store templates in version control
- Testing: Test templates in non-production environments first
- Monitoring: Monitor deployment status and logs
Export a Deployment as an ARM Template or Convert ARM Template to Bicep
Exporting Deployments
Azure allows you to export existing resource configurations as ARM templates, which can then be modified and redeployed or converted to Bicep files.
Azure Portal Export
Portal Export Process:
- Navigate to Resource Group: Go to Azure Portal → Resource groups → Select resource group
- Access Export Template: Click "Export template" in the left navigation
- Select Resources: Choose resources to include in the template
- Download Template: Download the generated ARM template
- Review Template: Review and modify the exported template
PowerShell Export
PowerShell Export Commands:
# Export resource group as ARM template Export-AzResourceGroup -ResourceGroupName "MyRG" -Path "exported-template.json" # Export specific resources Export-AzResourceGroup -ResourceGroupName "MyRG" -Resource "Microsoft.Storage/storageAccounts/mystorageaccount" -Path "storage-template.json" # Export with parameters Export-AzResourceGroup -ResourceGroupName "MyRG" -Path "exported-template.json" -IncludeParameterDefaultValue # Export with comments Export-AzResourceGroup -ResourceGroupName "MyRG" -Path "exported-template.json" -IncludeComments
Azure CLI Export
Azure CLI Export Commands:
# Export resource group as ARM template az group export --name MyRG --output-file exported-template.json # Export with parameters az group export --name MyRG --output-file exported-template.json --include-parameter-default-value # Export specific resources az resource list --resource-group MyRG --output table az resource export --ids /subscriptions/{subscription-id}/resourceGroups/MyRG/providers/Microsoft.Storage/storageAccounts/mystorageaccount --output-file storage-template.json
Converting ARM Templates to Bicep
Bicep CLI Conversion
Conversion Commands:
# Install Bicep CLI az bicep install # Convert ARM template to Bicep az bicep decompile --file template.json # Convert with output file az bicep decompile --file template.json --outfile template.bicep # Validate Bicep file az bicep build --file template.bicep # Build Bicep to ARM template az bicep build --file template.bicep --outfile compiled-template.json
Manual Conversion Guidelines
Conversion Best Practices:
- Parameters: Convert JSON parameters to Bicep parameter syntax
- Variables: Convert JSON variables to Bicep variable syntax
- Resources: Convert resource definitions to Bicep resource syntax
- Outputs: Convert JSON outputs to Bicep output syntax
- Functions: Update ARM template functions to Bicep equivalents
- Validation: Validate converted Bicep files
Advanced Template and Bicep Concepts
Template Functions
Common ARM Template Functions:
- resourceGroup(): Returns information about the current resource group
- subscription(): Returns information about the current subscription
- uniqueString(): Creates a deterministic hash string
- concat(): Combines multiple string values
- parameters(): Returns a parameter value
- variables(): Returns a variable value
- reference(): Returns runtime state of a resource
Bicep Functions
Common Bicep Functions:
- resourceGroup(): Returns resource group information
- subscription(): Returns subscription information
- uniqueString(): Creates deterministic hash string
- concat(): Combines string values
- resourceId(): Returns unique identifier of a resource
- reference(): Returns runtime state of a resource
- listKeys(): Returns keys for a resource
Advanced Deployment Scenarios
Scenario 1: Multi-Environment Deployment
Situation: Organization needs to deploy the same infrastructure to multiple environments (dev, test, prod) with different configurations.
Solution: Create parameter files for each environment, use Bicep modules for reusability, and implement deployment pipelines for automated deployments.
Scenario 2: Infrastructure Updates
Situation: Organization needs to update existing infrastructure without disrupting services.
Solution: Use incremental deployment mode, implement proper resource dependencies, and use What-If to preview changes before deployment.
Scenario 3: Disaster Recovery
Situation: Organization needs to quickly recreate infrastructure in a different region for disaster recovery.
Solution: Use ARM templates or Bicep files with location parameters, implement cross-region deployment capabilities, and maintain template version control.
Best Practices and Recommendations
Template Development Best Practices
✅ Development Recommendations:
- Modularity: Break templates into reusable modules
- Parameterization: Use parameters for customizable values
- Validation: Add parameter validation and constraints
- Documentation: Document template purpose and usage
- Version Control: Use version control for template management
- Testing: Test templates in non-production environments
- Security: Avoid hardcoding sensitive values
Deployment Best Practices
Deployment Recommendations:
- Incremental Mode: Use incremental deployment mode by default
- What-If Analysis: Always preview changes before deployment
- Validation: Validate templates before deployment
- Rollback Plan: Have a rollback strategy for failed deployments
- Monitoring: Monitor deployment status and resource health
- Automation: Use CI/CD pipelines for automated deployments
- Environment Separation: Separate environments with different parameter files
Monitoring and Troubleshooting
Deployment Monitoring
Key Monitoring Areas:
- Deployment Status: Monitor deployment progress and completion
- Resource Health: Check resource health after deployment
- Template Validation: Validate templates before deployment
- Parameter Validation: Ensure parameter values are correct
- Dependency Resolution: Monitor resource dependency resolution
- Error Logs: Review deployment error logs and messages
Common Issues and Solutions
⚠️ Common Problems:
- Template Validation Errors: Check JSON syntax and resource properties
- Parameter Validation Failures: Verify parameter values and constraints
- Resource Conflicts: Check for naming conflicts and resource limits
- Dependency Issues: Verify resource dependencies and order
- Permission Errors: Ensure proper RBAC permissions for deployment
- Quota Exceeded: Check subscription and resource group quotas
- Network Issues: Verify network connectivity and firewall rules
Exam Preparation Tips
Key Concepts to Remember
- Template Structure: Schema, parameters, variables, resources, outputs
- Bicep Advantages: Simplified syntax, type safety, modularity
- Deployment Methods: Portal, PowerShell, Azure CLI
- Template Functions: resourceGroup(), uniqueString(), concat(), reference()
- Deployment Modes: Incremental vs Complete deployment
- Validation: What-If analysis and template validation
- Export and Conversion: Exporting templates and converting to Bicep
Practice Questions
Sample Exam Questions:
- What is the difference between incremental and complete deployment modes?
- How do you deploy a Bicep file using PowerShell?
- What are the advantages of using Bicep over ARM templates?
- How do you export an existing resource group as an ARM template?
- What is the purpose of the What-If deployment feature?
- How do you convert an ARM template to a Bicep file?
- What are the key components of an ARM template?
- How do you validate a template before deployment?
- What is the purpose of template parameters?
- How do you reference one resource from another in a template?
AZ-104 Success Tip: ARM templates and Bicep files are essential for Infrastructure as Code in Azure. Focus on understanding template structure, deployment methods, and the differences between ARM templates and Bicep. Practice with PowerShell and Azure CLI commands for deployment operations, and understand how to export existing resources and convert between template formats. Pay attention to deployment modes, validation techniques, and common troubleshooting scenarios.
Related Topics
Continue your Azure administration learning journey with these related topics:
- Manage Azure Subscriptions and Governance - Implement governance policies for your infrastructure deployments
- Create and Configure Virtual Machines - Deploy VMs using ARM templates and Bicep
- Provision and Manage Containers - Deploy container infrastructure with IaC
- Create and Configure Azure App Service - Deploy App Service resources with templates
- Configure and Manage Storage Accounts - Deploy storage accounts with infrastructure as code
- Configure and Manage Virtual Networks - Deploy network infrastructure with templates
- Monitor Resources in Azure - Monitor your infrastructure deployments