arm-templates
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseARM Templates & Bicep
ARM模板与Bicep
Deploy Azure infrastructure with ARM templates and Bicep. Bicep is the recommended domain-specific language that compiles to ARM JSON, offering cleaner syntax, modules, and first-class tooling support.
使用ARM模板和Bicep部署Azure基础设施。Bicep是微软推荐的领域特定语言,可编译为ARM JSON,提供更简洁的语法、模块化能力以及一流的工具支持。
When to Use
适用场景
- You need Azure-native Infrastructure as Code without third-party tooling.
- Your organization standardizes on Azure and wants tight portal integration.
- You need What-If analysis before deploying changes.
- You are migrating existing ARM JSON templates to Bicep for maintainability.
- You need deployment scopes at resource group, subscription, management group, or tenant level.
- 你需要不依赖第三方工具的Azure原生基础设施即代码方案。
- 你的组织以Azure为标准化平台,需要与Azure门户深度集成。
- 你需要在部署变更前执行What-If分析。
- 你正在将现有ARM JSON模板迁移到Bicep以提升可维护性。
- 你需要在资源组、订阅、管理组或租户级别进行部署。
Prerequisites
前置条件
bash
undefinedbash
undefinedInstall Azure CLI
Install Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
Install Bicep CLI (bundled with Azure CLI 2.20+)
Install Bicep CLI (bundled with Azure CLI 2.20+)
az bicep install
az bicep upgrade
az bicep install
az bicep upgrade
Verify installation
Verify installation
az bicep version
az bicep version
Login and set subscription
Login and set subscription
az login
az account set --subscription "my-subscription-id"
undefinedaz login
az account set --subscription "my-subscription-id"
undefinedBicep Fundamentals
Bicep基础
Resource Group Deployment with Virtual Network
带虚拟网络的资源组部署
bicep
// main.bicep
@description('Azure region for all resources')
param location string = resourceGroup().location
@description('Environment name used for resource naming')
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'
@description('Base name for all resources')
param baseName string
var vnetName = '${baseName}-${environment}-vnet'
var nsgName = '${baseName}-${environment}-nsg'
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowHTTPS'
properties: {
priority: 100
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '443'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
}
}
{
name: 'DenyAllInbound'
properties: {
priority: 4096
direction: 'Inbound'
access: 'Deny'
protocol: '*'
sourcePortRange: '*'
destinationPortRange: '*'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
}
}
]
}
}
resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'web-subnet'
properties: {
addressPrefix: '10.0.1.0/24'
networkSecurityGroup: {
id: nsg.id
}
}
}
{
name: 'app-subnet'
properties: {
addressPrefix: '10.0.2.0/24'
}
}
{
name: 'data-subnet'
properties: {
addressPrefix: '10.0.3.0/24'
privateEndpointNetworkPolicies: 'Enabled'
}
}
]
}
}
output vnetId string = vnet.id
output webSubnetId string = vnet.properties.subnets[0].id
output appSubnetId string = vnet.properties.subnets[1].idbicep
// main.bicep
@description('Azure region for all resources')
param location string = resourceGroup().location
@description('Environment name used for resource naming')
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'
@description('Base name for all resources')
param baseName string
var vnetName = '${baseName}-${environment}-vnet'
var nsgName = '${baseName}-${environment}-nsg'
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowHTTPS'
properties: {
priority: 100
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '443'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
}
}
{
name: 'DenyAllInbound'
properties: {
priority: 4096
direction: 'Inbound'
access: 'Deny'
protocol: '*'
sourcePortRange: '*'
destinationPortRange: '*'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
}
}
]
}
}
resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'web-subnet'
properties: {
addressPrefix: '10.0.1.0/24'
networkSecurityGroup: {
id: nsg.id
}
}
}
{
name: 'app-subnet'
properties: {
addressPrefix: '10.0.2.0/24'
}
}
{
name: 'data-subnet'
properties: {
addressPrefix: '10.0.3.0/24'
privateEndpointNetworkPolicies: 'Enabled'
}
}
]
}
}
output vnetId string = vnet.id
output webSubnetId string = vnet.properties.subnets[0].id
output appSubnetId string = vnet.properties.subnets[1].idVM Deployment with Managed Identity
带托管标识的VM部署
bicep
// vm.bicep
param location string = resourceGroup().location
param vmName string
param subnetId string
param adminUsername string = 'azureuser'
@secure()
param adminPublicKey string
resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
name: '${vmName}-nic'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetId
}
}
}
]
}
}
resource vm 'Microsoft.Compute/virtualMachines@2023-07-01' = {
name: vmName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
hardwareProfile: {
vmSize: 'Standard_B2s'
}
osProfile: {
computerName: vmName
adminUsername: adminUsername
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminPublicKey
}
]
}
}
}
storageProfile: {
imageReference: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
}
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
}
]
}
diagnosticsProfile: {
bootDiagnostics: {
enabled: true
}
}
}
}
output vmPrincipalId string = vm.identity.principalId
output vmId string = vm.idbicep
// vm.bicep
param location string = resourceGroup().location
param vmName string
param subnetId string
param adminUsername string = 'azureuser'
@secure()
param adminPublicKey string
resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
name: '${vmName}-nic'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetId
}
}
}
]
}
}
resource vm 'Microsoft.Compute/virtualMachines@2023-07-01' = {
name: vmName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
hardwareProfile: {
vmSize: 'Standard_B2s'
}
osProfile: {
computerName: vmName
adminUsername: adminUsername
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: adminPublicKey
}
]
}
}
}
storageProfile: {
imageReference: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
}
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
}
]
}
diagnosticsProfile: {
bootDiagnostics: {
enabled: true
}
}
}
}
output vmPrincipalId string = vm.identity.principalId
output vmId string = vm.idBicep Modules
Bicep模块
Module Definition
模块定义
bicep
// modules/storage.bicep
@description('Storage account name (3-24 chars, lowercase alphanumeric)')
param storageAccountName string
param location string = resourceGroup().location
param sku string = 'Standard_LRS'
@allowed(['Hot', 'Cool', 'Archive'])
param accessTier string = 'Hot'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: sku
}
kind: 'StorageV2'
properties: {
accessTier: accessTier
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
networkAcls: {
defaultAction: 'Deny'
bypass: 'AzureServices'
}
}
}
output storageAccountId string = storageAccount.id
output primaryBlobEndpoint string = storageAccount.properties.primaryEndpoints.blobbicep
// modules/storage.bicep
@description('Storage account name (3-24 chars, lowercase alphanumeric)')
param storageAccountName string
param location string = resourceGroup().location
param sku string = 'Standard_LRS'
@allowed(['Hot', 'Cool', 'Archive'])
param accessTier string = 'Hot'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: sku
}
kind: 'StorageV2'
properties: {
accessTier: accessTier
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
networkAcls: {
defaultAction: 'Deny'
bypass: 'AzureServices'
}
}
}
output storageAccountId string = storageAccount.id
output primaryBlobEndpoint string = storageAccount.properties.primaryEndpoints.blobConsuming Modules
调用模块
bicep
// main.bicep
param location string = resourceGroup().location
param environment string = 'prod'
module storage 'modules/storage.bicep' = {
name: 'storage-deployment'
params: {
storageAccountName: 'myapp${environment}sa'
location: location
sku: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
}
}
module vnet 'modules/network.bicep' = {
name: 'vnet-deployment'
params: {
location: location
environment: environment
}
}
// Reference module outputs
output storageBlobEndpoint string = storage.outputs.primaryBlobEndpointbicep
// main.bicep
param location string = resourceGroup().location
param environment string = 'prod'
module storage 'modules/storage.bicep' = {
name: 'storage-deployment'
params: {
storageAccountName: 'myapp${environment}sa'
location: location
sku: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
}
}
module vnet 'modules/network.bicep' = {
name: 'vnet-deployment'
params: {
location: location
environment: environment
}
}
// Reference module outputs
output storageBlobEndpoint string = storage.outputs.primaryBlobEndpointARM JSON Template Structure
ARM JSON模板结构
json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"metadata": {
"description": "Name of the storage account"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"storageSku": "Standard_LRS"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[variables('storageSku')]"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true,
"minimumTlsVersion": "TLS1_2"
}
}
],
"outputs": {
"storageId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
}
}
}json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"metadata": {
"description": "Name of the storage account"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"storageSku": "Standard_LRS"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[variables('storageSku')]"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true,
"minimumTlsVersion": "TLS1_2"
}
}
],
"outputs": {
"storageId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
}
}
}Deployment Commands
部署命令
bash
undefinedbash
undefinedValidate a Bicep template before deployment
Validate a Bicep template before deployment
az deployment group validate
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
az deployment group validate
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
Preview changes with What-If
Preview changes with What-If
az deployment group what-if
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
az deployment group what-if
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
Deploy Bicep to resource group
Deploy Bicep to resource group
az deployment group create
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--name "deploy-$(date +%Y%m%d-%H%M%S)"
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--name "deploy-$(date +%Y%m%d-%H%M%S)"
az deployment group create
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--name "deploy-$(date +%Y%m%d-%H%M%S)"
--resource-group mygroup
--template-file main.bicep
--parameters environment='prod' baseName='myapp'
--name "deploy-$(date +%Y%m%d-%H%M%S)"
Deploy ARM JSON with parameter file
Deploy ARM JSON with parameter file
az deployment group create
--resource-group mygroup
--template-file template.json
--parameters @parameters.prod.json
--resource-group mygroup
--template-file template.json
--parameters @parameters.prod.json
az deployment group create
--resource-group mygroup
--template-file template.json
--parameters @parameters.prod.json
--resource-group mygroup
--template-file template.json
--parameters @parameters.prod.json
Subscription-level deployment (e.g., resource groups, policies)
Subscription-level deployment (e.g., resource groups, policies)
az deployment sub create
--location eastus
--template-file subscription-level.bicep
--parameters @params.json
--location eastus
--template-file subscription-level.bicep
--parameters @params.json
az deployment sub create
--location eastus
--template-file subscription-level.bicep
--parameters @params.json
--location eastus
--template-file subscription-level.bicep
--parameters @params.json
Management group deployment
Management group deployment
az deployment mg create
--management-group-id my-mg
--location eastus
--template-file mg-policy.bicep
--management-group-id my-mg
--location eastus
--template-file mg-policy.bicep
az deployment mg create
--management-group-id my-mg
--location eastus
--template-file mg-policy.bicep
--management-group-id my-mg
--location eastus
--template-file mg-policy.bicep
Export resource group to ARM JSON
Export resource group to ARM JSON
az group export --name mygroup --output json > exported-template.json
az group export --name mygroup --output json > exported-template.json
Decompile ARM JSON to Bicep
Decompile ARM JSON to Bicep
az bicep decompile --file exported-template.json
az bicep decompile --file exported-template.json
Build Bicep to ARM JSON (for inspection)
Build Bicep to ARM JSON (for inspection)
az bicep build --file main.bicep --outfile main.json
az bicep build --file main.bicep --outfile main.json
List deployments and their status
List deployments and their status
az deployment group list
--resource-group mygroup
--output table
--resource-group mygroup
--output table
az deployment group list
--resource-group mygroup
--output table
--resource-group mygroup
--output table
Delete a failed deployment
Delete a failed deployment
az deployment group delete
--resource-group mygroup
--name my-failed-deployment
--resource-group mygroup
--name my-failed-deployment
undefinedaz deployment group delete
--resource-group mygroup
--name my-failed-deployment
--resource-group mygroup
--name my-failed-deployment
undefinedParameter Files
参数文件
json
// parameters.prod.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": { "value": "prod" },
"baseName": { "value": "myapp" },
"adminPublicKey": {
"reference": {
"keyVault": {
"id": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault}"
},
"secretName": "ssh-public-key"
}
}
}
}json
// parameters.prod.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": { "value": "prod" },
"baseName": { "value": "myapp" },
"adminPublicKey": {
"reference": {
"keyVault": {
"id": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault}"
},
"secretName": "ssh-public-key"
}
}
}
}Linked and Nested Templates
链接与嵌套模板
bicep
// Deploy to a different resource group
module networkInSharedRg 'modules/network.bicep' = {
name: 'shared-network'
scope: resourceGroup('shared-networking-rg')
params: {
location: location
}
}
// Conditional deployment
param deployMonitoring bool = true
module monitoring 'modules/monitoring.bicep' = if (deployMonitoring) {
name: 'monitoring-deployment'
params: {
location: location
}
}
// Loop deployment
param storageAccounts array = [
{ name: 'logs', sku: 'Standard_LRS' }
{ name: 'data', sku: 'Standard_GRS' }
]
module storageLoop 'modules/storage.bicep' = [for account in storageAccounts: {
name: 'storage-${account.name}'
params: {
storageAccountName: '${baseName}${account.name}sa'
sku: account.sku
location: location
}
}]bicep
// Deploy to a different resource group
module networkInSharedRg 'modules/network.bicep' = {
name: 'shared-network'
scope: resourceGroup('shared-networking-rg')
params: {
location: location
}
}
// Conditional deployment
param deployMonitoring bool = true
module monitoring 'modules/monitoring.bicep' = if (deployMonitoring) {
name: 'monitoring-deployment'
params: {
location: location
}
}
// Loop deployment
param storageAccounts array = [
{ name: 'logs', sku: 'Standard_LRS' }
{ name: 'data', sku: 'Standard_GRS' }
]
module storageLoop 'modules/storage.bicep' = [for account in storageAccounts: {
name: 'storage-${account.name}'
params: {
storageAccountName: '${baseName}${account.name}sa'
sku: account.sku
location: location
}
}]Troubleshooting
故障排查
| Symptom | Cause | Fix |
|---|---|---|
| Syntax error in ARM JSON or Bicep | Run |
| Resource dependency not declared | Add |
| Subscription quota exceeded | Request quota increase or use a different region |
| Insufficient RBAC permissions | Assign Contributor role on the target resource group |
| Parameter file secrets in source control | Secrets stored as plain text | Use Key Vault references in parameter files |
| Deployment takes very long | Large number of resources deployed serially | Use |
| Complete mode instead of Incremental | Use |
| Bicep module not found | Incorrect relative path | Verify path is relative to the consuming file |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| ARM JSON或Bicep存在语法错误 | 运行 |
部署期间出现 | 未声明资源依赖 | 在Bicep中添加 |
出现 | 订阅配额不足 | 请求提升配额或更换区域 |
| RBAC权限不足 | 为目标资源组分配Contributor角色 |
| 参数文件中的密钥存入版本控制 | 密钥以明文存储 | 在参数文件中使用Key Vault引用 |
| 部署耗时极长 | 大量资源串行部署 | 合理使用 |
| 使用了Complete模式而非Incremental模式 | 使用默认的 |
| Bicep模块未找到 | 相对路径错误 | 验证路径相对于调用文件的正确性 |
Related Skills
相关技能
- -- Multi-cloud IaC alternative with broader provider support.
terraform-azure - -- VNet, NSG, and firewall configurations referenced in templates.
azure-networking - -- Virtual machine sizing and configuration details.
azure-vms - -- Kubernetes cluster definitions for Bicep/ARM.
azure-aks
- -- 支持多云的IaC替代方案,拥有更广泛的提供商支持。
terraform-azure - -- 模板中引用的VNet、NSG和防火墙配置。
azure-networking - -- 虚拟机规格与配置细节。
azure-vms - -- 适用于Bicep/ARM的Kubernetes集群定义。
azure-aks