Skip to content

Deployment Templates

Lab Objective

In this hands-on lab, you will learn how to:

  • Interpret ARM template structure including schema, parameters, variables, resources, and outputs sections
  • Deploy infrastructure using ARM templates through Azure portal, CLI, and PowerShell methods
  • Convert ARM templates to Bicep using decompilation tools and understand syntax differences
  • Create modular Bicep files with parameters, variables, modules, and conditional deployment logic
  • Implement template security best practices including parameter validation, secure string handling, and RBAC integration
  • Troubleshoot deployment failures using activity logs, deployment history, and validation techniques
  • Optimize template performance through dependency management, parallel deployments, and resource organization

Scenario: Your organization needs to standardize infrastructure deployments across development, staging, and production environments. You’ll create and deploy Infrastructure as Code (IaC) solutions using both ARM templates and Bicep files to ensure consistent, repeatable, and secure Azure resource provisioning while maintaining compliance and governance standards.


Pre-Provisioned Environment

The following Azure resources have been pre-deployed in your environment:

Resource Overview

Resource TypeResource NameConfigurationPurpose
Resource GroupDeploymentTemplates-Lab-RGContains all lab resourcesLogical container
Storage Accounttemplatesstore[unique]GPv2, Hot tier, LRSTemplate and artifact storage
Key Vaulttemplateskv[unique]Standard tier, RBAC enabledSecure parameter storage
Virtual Networktemplates-vnet10.0.0.0/16 address spaceNetwork infrastructure
Test VMDeploymentTemplatesVMWindows Server 2019Template testing and validation
Container Registrytemplatesacr[unique]Basic tierContainer image storage
Log Analyticstemplateslog[unique]Standard workspaceDeployment monitoring

Template Storage Structure

Template Storage Account (templatesstore[unique])
β”œβ”€β”€ Container: arm-templates
β”‚ β”œβ”€β”€ /basic/
β”‚ β”‚ β”œβ”€β”€ storage-account.json
β”‚ β”‚ β”œβ”€β”€ virtual-network.json
β”‚ β”‚ └── virtual-machine.json
β”‚ β”œβ”€β”€ /advanced/
β”‚ β”‚ β”œβ”€β”€ multi-tier-app.json
β”‚ β”‚ β”œβ”€β”€ linked-templates/
β”‚ β”‚ └── nested-templates/
β”‚ └── /parameters/
β”‚ β”œβ”€β”€ dev-parameters.json
β”‚ β”œβ”€β”€ staging-parameters.json
β”‚ └── prod-parameters.json
β”œβ”€β”€ Container: bicep-files
β”‚ β”œβ”€β”€ /modules/
β”‚ β”‚ β”œβ”€β”€ storage.bicep
β”‚ β”‚ β”œβ”€β”€ network.bicep
β”‚ β”‚ └── compute.bicep
β”‚ β”œβ”€β”€ /main-templates/
β”‚ β”‚ β”œβ”€β”€ webapp-deployment.bicep
β”‚ β”‚ └── infrastructure.bicep
β”‚ └── /examples/
β”‚ β”œβ”€β”€ conditional-resources.bicep
β”‚ └── loops-and-conditions.bicep
└── Container: deployment-artifacts
β”œβ”€β”€ /scripts/
β”œβ”€β”€ /configs/
└── /certificates/

Key Vault Secrets Configuration

Secret NamePurposeExample Value
AdminPasswordVM administrator passwordSecure random password
DatabaseConnectionStringApplication database connectionEncrypted connection string
StorageAccountKeyStorage access keyPrimary access key
CertificateThumbprintSSL certificate identifierCertificate thumbprint

Network Topology

Virtual Network (templates-vnet - 10.0.0.0/16)
β”œβ”€β”€ ManagementSubnet (10.0.1.0/24)
β”‚ └── DeploymentTemplatesVM (10.0.1.4)
β”œβ”€β”€ WebSubnet (10.0.2.0/24)
β”‚ └── [Available for template deployments]
β”œβ”€β”€ DataSubnet (10.0.3.0/24)
β”‚ └── [Available for template deployments]
└── ContainerSubnet (10.0.4.0/24)
└── [Available for ACI deployments]

Pre-configured Template Examples

Template TypeFile NameResources CreatedComplexity
Basic Storagestorage-account.jsonStorage account with containersBeginner
Virtual Networkvirtual-network.jsonVNet, subnets, NSGsBeginner
Virtual Machinevirtual-machine.jsonVM, NIC, disk, public IPIntermediate
Multi-tier Appmulti-tier-app.jsonLoad balancer, VMs, databaseAdvanced
Container Workloadcontainer-deployment.bicepACI, storage, networkingIntermediate

Lab Exercises

Part 1: Understand ARM Template Structure

Step 1: Examine Basic ARM Template Components

  1. Navigate to Storage accounts in the Azure portal
  2. Click on templatesstore[unique]
  3. Go to Storage browser β†’ Blob containers
  4. Click on arm-templates container
  5. Navigate to /basic/ folder
  6. Download storage-account.json

Template analysis:

  • Schema version: Identifies ARM template format and API version
  • ContentVersion: Template versioning for change tracking
  • Parameters section: Define input values with types and constraints
  • Variables section: Computed values and reusable expressions
  • Resources section: Azure resources to be created or modified
  • Outputs section: Values returned after successful deployment

Step 2: Analyze Template Parameters and Variables

  1. Open the downloaded storage-account.json in your preferred editor
  2. Examine the parameters section:

Parameter structure analysis:

  • storageAccountName: String parameter with naming constraints
  • storageAccountType: Allowed values restricting SKU options
  • location: Default value using resource group location function
  • tags: Object parameter for resource tagging strategy

Step 3: Review Resource Dependencies

  1. Navigate back to the arm-templates container
  2. Download multi-tier-app.json
  3. Open the file and examine the resources array

Dependency analysis:

  • Implicit dependencies: References using resource functions
  • Explicit dependencies: "dependsOn" array declarations
  • Parallel deployment: Resources without dependencies deploy simultaneously
  • Deployment ordering: Critical for network, storage, and compute resources

Part 2: Deploy ARM Templates

Step 1: Deploy Template Using Azure Portal

  1. Navigate to Resource groups and click DeploymentTemplates-Lab-RG
  2. Click β€œDeploy a custom template”
  3. Click β€œBuild your own template in the editor”
  4. Copy and paste the content from storage-account.json

Template deployment configuration:

  • Storage account name: Enter armdeploy[unique]
  • Storage account type: Select Standard_LRS
  • Location: Use resource group location
  • Tags: Add Environment: Lab and Purpose: ARM-Demo

Step 2: Monitor Deployment Progress

  1. Click β€œReview + create” then click β€œCreate”
  2. Navigate to the deployment blade to monitor progress
  3. Observe the deployment timeline and resource creation order

Deployment monitoring:

  • Deployment status: Track overall progress and completion
  • Resource creation: Individual resource deployment status
  • Duration metrics: Time taken for each deployment phase
  • Error handling: Automatic rollback on validation failures

Step 3: Validate Deployed Resources

  1. Navigate to the newly created storage account armdeploy[unique]
  2. Verify the configuration matches template specifications
  3. Check the tags were applied correctly

Validation checklist:

  • Storage account exists with correct name and SKU
  • Resource tags match template parameters
  • Location matches resource group location
  • Access tier and replication settings are correct

Part 3: Work with Bicep Files

Step 1: Install and Configure Bicep Tools

  1. Connect to DeploymentTemplatesVM using RDP
  2. Open PowerShell as Administrator
  3. Install Bicep CLI and VS Code extension

Bicep tooling setup:

  • Bicep CLI: Command-line interface for compilation and deployment
  • VS Code extension: IntelliSense, syntax highlighting, and validation
  • Azure CLI integration: Native Bicep support in Azure CLI
  • PowerShell module: Az.Bicep module for PowerShell workflows

Step 2: Convert ARM Template to Bicep

  1. Download virtual-network.json from the templates storage
  2. Open command prompt in the download location
  3. Run: az bicep decompile --file virtual-network.json

Bicep conversion analysis:

  • Syntax simplification: Reduced JSON verbosity and improved readability
  • Type safety: Strong typing and compile-time validation
  • Resource references: Simplified symbolic name referencing
  • Parameter handling: Cleaner parameter and variable declarations

Step 3: Create Custom Bicep Module

  1. Create a new file named webapp-module.bicep
  2. Define parameters for web app configuration:

Module structure:

  • Parameters: Input values for customization
  • Resources: Web app, app service plan, and dependencies
  • Outputs: Resource identifiers and configuration values
  • Metadata: Documentation and versioning information

Step 4: Test Bicep Compilation

  1. Compile the Bicep file: az bicep build --file webapp-module.bicep
  2. Review the generated ARM template JSON
  3. Validate the template: az deployment group validate

Compilation validation:

  • Syntax errors and type checking
  • Resource provider API validation
  • Parameter and variable resolution
  • Dependency graph verification

Part 4: Implement Advanced Template Features

Step 1: Create Conditional Resource Deployment

  1. Navigate to the bicep-files container in storage
  2. Download conditional-resources.bicep
  3. Examine the conditional deployment logic

Conditional deployment patterns:

  • Environment-based resources: Deploy different resources per environment
  • Feature flags: Enable/disable functionality through parameters
  • Cost optimization: Deploy optional resources based on requirements
  • Compliance controls: Conditional security and monitoring resources

Step 2: Implement Template Loops

  1. Open loops-and-conditions.bicep from the examples folder
  2. Study the array iteration and resource creation patterns

Loop implementation:

  • Copy operations: Create multiple similar resources
  • Variable loops: Generate configuration arrays
  • Conditional loops: Combine conditions with iterations
  • Nested loops: Complex resource relationships and dependencies

Step 3: Create Linked Template Deployment

  1. Navigate to /advanced/linked-templates/ in the ARM templates container
  2. Examine the main template and linked template structure
  3. Deploy the linked template solution

Linked template benefits:

  • Modularity: Separate concerns and reusable components
  • Team collaboration: Different teams can work on different templates
  • Template size limits: Overcome single template size restrictions
  • Deployment orchestration: Complex multi-stage deployments

Part 5: Secure Template Deployment

Step 1: Implement Secure Parameter Handling

  1. Navigate to Key Vault templateskv[unique]
  2. Create a new secret named DeploymentSecret
  3. Set the value to a complex password

Key Vault integration:

  • Secure parameters: Reference Key Vault secrets in templates
  • RBAC permissions: Grant template deployment access to secrets
  • Secret versioning: Manage secret lifecycle and rotation
  • Audit logging: Track secret access and usage patterns

Step 2: Configure Template RBAC

  1. Go to Resource groups β†’ DeploymentTemplates-Lab-RG
  2. Click β€œAccess control (IAM)”
  3. Add role assignment for template deployment service principal

RBAC configuration:

  • Contributor role: Required for resource creation and modification
  • Reader role: Minimum permission for template validation
  • Custom roles: Granular permissions for specific deployment scenarios
  • Managed identity: Secure authentication for automated deployments

Step 3: Validate Template Security

  1. Download a template with Key Vault references
  2. Deploy using secure parameter retrieval
  3. Monitor the deployment for security compliance

Security validation:

  • No secrets stored in template or parameter files
  • Proper RBAC assignments for deployment identity
  • Secure parameter transmission and storage
  • Compliance with organizational security policies

Part 6: Monitor and Troubleshoot Deployments

Step 1: Analyze Deployment History

  1. Navigate to Resource groups β†’ DeploymentTemplates-Lab-RG
  2. Click β€œDeployments” under Settings
  3. Review the deployment history and status

Deployment history analysis:

  • Success rates: Track deployment reliability over time
  • Duration trends: Identify performance improvements or regressions
  • Failure patterns: Common deployment issues and resolutions
  • Resource changes: Track infrastructure modifications and impacts

Step 2: Troubleshoot Failed Deployment

  1. Click on a failed deployment from the history
  2. Examine the error details and affected resources
  3. Navigate to Activity Log for detailed error information

Troubleshooting methodology:

  • Error message analysis: Understanding Azure error formats and codes
  • Resource-level debugging: Individual resource creation failures
  • Dependency issues: Identify circular or missing dependencies
  • Parameter validation: Verify input values and constraints

Step 3: Implement Deployment Monitoring

  1. Navigate to Log Analytics workspace templateslog[unique]
  2. Create queries to monitor deployment metrics
  3. Set up alerts for deployment failures

Monitoring implementation:

  • Deployment logs: Centralized logging for all template deployments
  • Performance metrics: Track deployment duration and resource utilization
  • Error alerting: Automated notifications for deployment failures
  • Compliance reporting: Audit trails for governance and compliance

Troubleshooting Guide

Common Deployment Template Issues

IssueSymptomsPossible CauseSolution
Template validation failedDeployment fails before resource creationInvalid JSON syntax or schema violationsValidate template structure and fix syntax errors using Azure CLI or portal
Resource already existsDeployment fails with conflict errorResource name collision or incomplete cleanupUse unique naming conventions or implement conditional deployment logic
Permission deniedDeployment fails with authorization errorInsufficient RBAC permissions for deployment identityGrant appropriate roles (Contributor) to service principal or user identity
Dependency cycle detectedDeployment hangs or fails with circular referenceResources reference each other in circular patternReview and restructure resource dependencies to eliminate cycles
Parameter validation failedTemplate accepts invalid parameter valuesMissing parameter constraints or validation rulesAdd allowed values, min/max length, and regex patterns for parameters

Template Configuration Checklist

ComponentRequirementStatusNotes
Schema versionLatest ARM template schema (2019-04-01 or newer)βœ…Ensures access to latest features and functions
Parameter validationConstraints defined for all input parametersβœ…Prevents invalid values and improves security
Resource dependenciesProper dependency declaration and orderingβœ…Ensures correct deployment sequence
Secret handlingKey Vault references for sensitive parametersβœ…Prevents credential exposure in templates
Error handlingRollback and cleanup procedures definedβœ…Maintains environment consistency on failures

Best Practices

ScenarioRecommendationBenefit
Large deploymentsUse linked or nested templates for modularityImproves maintainability and enables team collaboration
Multi-environmentParameterize environment-specific valuesSingle template supports dev, staging, and production
Security complianceStore secrets in Key Vault and use managed identitiesMeets enterprise security and compliance requirements
Performance optimizationMinimize dependencies and leverage parallel deploymentReduces deployment time and improves reliability
Version controlTag templates and maintain deployment historyEnables rollback and change tracking capabilities

Optional Advanced Exercises

For users wanting more technical depth, try these exercises:

Advanced Exercise 1: Automated Template Deployment

Terminal window
# Deploy ARM templates using PowerShell with parameter files
Connect-AzAccount
# Set up variables for automated deployment
$resourceGroup = "DeploymentTemplates-Lab-RG"
$templateFile = "C:\Templates\multi-tier-app.json"
$parameterFile = "C:\Templates\prod-parameters.json"
$deploymentName = "AutomatedDeployment-$(Get-Date -Format 'yyyyMMddHHmmss')"
# Deploy template with monitoring
$deployment = New-AzResourceGroupDeployment -ResourceGroupName $resourceGroup -TemplateFile $templateFile -TemplateParameterFile $parameterFile -Name $deploymentName -Verbose
# Monitor deployment progress
do {
Start-Sleep -Seconds 30
$status = Get-AzResourceGroupDeployment -ResourceGroupName $resourceGroup -Name $deploymentName
Write-Host "Deployment Status: $($status.ProvisioningState) - $($status.Timestamp)"
} while ($status.ProvisioningState -eq "Running")
Write-Host "Deployment completed with status: $($status.ProvisioningState)"

Advanced Exercise 2: Bicep Module Development

Terminal window
# Create and deploy modular Bicep architecture
$resourceGroup = "DeploymentTemplates-Lab-RG"
$bicepFile = "infrastructure.bicep"
$location = "East US"
# Compile Bicep to ARM template
az bicep build --file $bicepFile --outfile infrastructure.json
# Validate compiled template
$validation = Test-AzResourceGroupDeployment -ResourceGroupName $resourceGroup -TemplateFile "infrastructure.json" -location $location -storageAccountPrefix "bicepstore"
if ($validation.Count -eq 0) {
# Deploy if validation passes
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroup -TemplateFile "infrastructure.json" -location $location -storageAccountPrefix "bicepstore" -Verbose
Write-Host "Bicep deployment completed successfully"
} else {
Write-Host "Template validation failed:"
$validation | ForEach-Object { Write-Host $_.Message }
}

Advanced Exercise 3: Template Deployment Monitoring

Terminal window
# Advanced deployment monitoring and alerting
$resourceGroup = "DeploymentTemplates-Lab-RG"
$workspaceName = "templateslog[unique]"
# Query deployment logs using KQL
$query = @"
AzureActivity
| where TimeGenerated > ago(24h)
| where CategoryValue == "Administrative"
| where OperationNameValue contains "deployments"
| where ResourceGroup == "$resourceGroup"
| summarize Count=count() by OperationNameValue, ActivityStatusValue, bin(TimeGenerated, 1h)
| order by TimeGenerated desc
"@
# Execute query and analyze results
$workspace = Get-AzOperationalInsightsWorkspace -ResourceGroupName $resourceGroup -Name $workspaceName
$results = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspace.CustomerId -Query $query
# Display deployment metrics
Write-Host "Deployment Activity Summary:"
$results.Results | Format-Table -AutoSize
# Create alert rule for deployment failures
$actionGroup = Get-AzActionGroup -ResourceGroupName $resourceGroup -Name "DeploymentAlerts"
$alertRule = New-AzMetricAlertRuleV2 -ResourceGroupName $resourceGroup -Name "TemplateDeploymentFailures" -TargetResourceId $workspace.ResourceId -WindowSize "00:15:00" -Frequency "00:05:00" -MetricName "DeploymentFailures" -Operator GreaterThan -Threshold 0 -Severity 2 -ActionGroup $actionGroup
Write-Host "Deployment monitoring and alerting configured successfully"

Key Takeaways

After completing this lab, you should understand:

  • ARM template structure provides a declarative approach to infrastructure deployment with proper dependency management and parameter validation
  • Bicep simplifies infrastructure as code by offering improved syntax, type safety, and development experience while maintaining ARM template compatibility
  • Template modularity and reusability enable efficient infrastructure management across multiple environments and deployment scenarios
  • Security best practices including Key Vault integration, RBAC configuration, and secure parameter handling protect sensitive deployment information
  • Deployment monitoring and troubleshooting techniques help identify and resolve infrastructure deployment issues quickly and effectively
  • Advanced template features such as conditional deployment, loops, and linked templates support complex enterprise infrastructure requirements

Deployment Templates Decision Matrix

Template Format Selection

CriteriaARM Templates (JSON)BicepAzure CLIRecommendation
Learning curveModerate complexityEasy to learnCommand-basedBicep for new projects, ARM for existing
Tooling supportMature ecosystemGrowing rapidlyBuilt-in Azure CLIBicep with VS Code for best experience
Enterprise adoptionWidely establishedIncreasing adoptionLimited IaC capabilityARM for legacy, Bicep for greenfield
Team collaborationVersion control friendlyExcellent readabilityScript-based sharingBicep for collaborative development

Deployment Strategy Selection

ScenarioTemplate ApproachExpected Outcome
Single environmentStandalone templates with hardcoded valuesFast deployment with minimal complexity
Multi-environmentParameterized templates with environment filesConsistent deployments with environment-specific configurations
Enterprise scaleLinked templates with modular architectureScalable infrastructure management with team collaboration
CI/CD integrationAutomated deployments with validation gatesReliable infrastructure delivery with quality assurance

Cost vs Complexity Trade-offs

Deployment PatternDevelopment EffortMaintenance CostOperational Benefit
Simple templatesLow initial investmentHigher long-term maintenanceQuick deployment with manual oversight
Modular architectureHigher upfront developmentLower ongoing maintenanceAutomated deployment with consistency
Enterprise frameworkSignificant initial investmentMinimal operational overheadFull automation with governance and compliance

Additional Resources