练习 - 重构 Bicep 文件
在上一练习中,你创建了一个初始 Bicep 文件,其中包含玩具卡车虚拟机和关联的资源。 但是,Bicep 模板没有遵循最佳做法,较难看懂。 在此单元中,你将重构改文件。
在重构过程中,你将:
- 更新资源和参数的符号名称。
- 删除冗余的参数、资源和属性。
- 添加变量和参数以使 Bicep 文件可重复使用。
更新资源符号名称
在 Visual Studio Code 中,打开 main.bicep 文件。
选择网络安全组资源的符号名称,即
networkSecurityGroups_ToyTruckServer_nsg_name_resource
或类似名称。重命名符号名称。 可以选择 F2 或者右键单击,然后选择“重命名符号”。
输入名称
networkSecurityGroup
,然后按 Enter。 Visual Studio Code 会更新文件中的名称和所有引用。对每个资源重复此过程。 重命名资源,如下表所示。
注意
部署中资源的名称与表中的名称略有不同。 查找其名称与这些名称相近的资源。
资源类型 当前符号名称 新符号名称 公共 IP 地址 publicIPAddresses_ToyTruckServer_ip_name_resource
publicIPAddress
虚拟机 virtualMachines_ToyTruckServer_name_resource
virtualMachine
虚拟网络 virtualNetworks_ToyTruck_vnet_name_resource
virtualNetwork
子网 virtualNetworks_ToyTruck_vnet_name_default
defaultSubnet
Linux networkInterfaces_toytruckserver890_name_resource
networkInterface
删除冗余的子网资源
虚拟网络的子网当前定义了两次。 它在 virtualNetwork
资源中定义了一次,并在第二次定义为它自己的子资源,名为 defaultSubnet
。 定义子网两次没有意义。
删除
defaultSubnet
资源。请注意,
networkInterface
资源现在显示一个问题,因为它引用了默认子网的资源 ID:更新
virtualNetwork
资源以包含对子网的existing
引用。 如果添加existing
引用,则可以在 Bicep 代码中再次引用子网,而无需再次定义:resource virtualNetwork 'Microsoft.Network/virtualNetworks@2020-11-01' = { name: virtualNetworks_ToyTruck_vnet_name location: 'westus' properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: 'default' properties: { addressPrefix: '10.0.0.0/24' delegations: [] privateEndpointNetworkPolicies: 'Enabled' privateLinkServiceNetworkPolicies: 'Enabled' } } ] virtualNetworkPeerings: [] enableDdosProtection: false } resource defaultSubnet 'subnets' existing = { name: 'default' } }
更新
networkInterface
资源以引用子网的资源 ID:resource networkInterface 'Microsoft.Network/networkInterfaces@2022-05-01' = { name: networkInterfaces_toytruckserver890_name location: 'westus3' properties: { ipConfigurations: [ { name: 'ipconfig1' properties: { privateIPAddress: '10.0.0.4' privateIPAllocationMethod: 'Dynamic' publicIPAddress: { id: publicIPAddress.id } subnet: { id: virtualNetwork::defaultSubnet.id } primary: true privateIPAddressVersion: 'IPv4' } } ] dnsSettings: { dnsServers: [] } enableAcceleratedNetworking: true enableIPForwarding: false disableTcpStateTracking: false networkSecurityGroup: { id: networkSecurityGroup.id } nicType: 'Standard' } }
你会注意到有关表达式在循环中涉及的错误。 你将在下一步中修复该问题。
转到
virtualNetwork
资源的subnets
属性并删除id: defaultSubnet.id
以解决错误。
将参数更改为变量
模板中的参数不一定是参数。 现在将参数重命名为更有意义的名称,并将其转换为变量。
选择
virtualNetworks_ToyTruck_vnet_name
参数的符号名称。 将其重命名为virtualNetworkName
。将参数更改为变量。 请记住删除类型,因为变量定义不包括类型:
var virtualNetworkName = 'ToyTruck-vnet'
对每个参数重复该过程。 重命名参数,如下表所示。
请注意,
networkInterfaceName
的值包含一个三位数。 不同部署的数字不同。 确保从引用模板复制变量的值。当前参数名称 新变量名称 virtualMachines_ToyTruckServer_name
virtualMachineName
networkInterfaces_toytruckserver890_name
networkInterfaceName
publicIPAddresses_ToyTruckServer_ip_name
publicIPAddressName
networkSecurityGroups_ToyTruckServer_nsg_name
networkSecurityGroupName
验证变量声明是否如以下示例所示:
var virtualNetworkName = 'ToyTruck-vnet' var virtualMachineName = 'ToyTruckServer' var networkInterfaceName = 'YOUR-NETWORK-INTERFACE-NAME' var publicIPAddressName = 'ToyTruckServer-ip' var networkSecurityGroupName = 'ToyTruckServer-nsg'
更新资源位置
当前,所有资源都使用硬编码的位置。 你现在将添加一个参数,以便模板变得更可重复使用。
在文件顶部,添加一个新的参数和描述修饰器,以明确该参数的用途:
@description('The location where resources are deployed.') param location string = resourceGroup().location
更新每个资源以使用
location
参数而不是硬编码的westus3
位置。
添加参数和变量
你的模板具有一些硬编码值,其中的参数或变量更适合。 现在将为可能在部署之间更改的属性添加参数,并为不会更改的值添加变量。
在 main.bicep 文件顶部
location
参数的下面,添加以下参数:@description('The name of the size of the virtual machine to deploy.') param virtualMachineSizeName string = 'Standard_D2s_v3' @description('The name of the storage account SKU to use for the virtual machine\'s managed disk.') param virtualMachineManagedDiskStorageAccountType string = 'Premium_LRS' @description('The administrator username for the virtual machine.') param virtualMachineAdminUsername string = 'toytruckadmin' @description('The administrator password for the virtual machine.') @secure() param virtualMachineAdminPassword string @description('The name of the SKU of the public IP address to deploy.') param publicIPAddressSkuName string = 'Standard' @description('The virtual network address range.') param virtualNetworkAddressPrefix string @description('The default subnet address range within the virtual network') param virtualNetworkDefaultSubnetAddressPrefix string
某些参数具有默认值,而其他参数则没有。 稍后,你将创建一个参数文件来设置其中的大多数值。
在
networkSecurityGroupName
变量下方添加以下新变量声明:var virtualNetworkDefaultSubnetName = 'default' var virtualMachineImageReference = { publisher: 'canonical' offer: '0001-com-ubuntu-server-focal' sku: '20_04-lts-gen2' version: 'latest' }
添加以下变量声明。 将这些值替换为自己的引用模板中的 OS 磁盘名称。
var virtualMachineOSDiskName = 'YOUR-OS-DISK-NAME'
virtualMachineOSDiskName
的值是唯一的。 每个部署的值都是不同的。 确保从引用模板复制变量的值。警告
请确保复制
virtualMachineOSDiskName
和networkInterfaceName
变量的正确的值。 否则,Azure 将无法检测到你声明的现有资源,并且可能会尝试创建新资源。变量声明现在应如以下示例所示:
var virtualNetworkName = 'ToyTruck-vnet' var virtualMachineName = 'ToyTruckServer' var networkInterfaceName = 'YOUR-NETWORK-INTERFACE-NAME' var publicIPAddressName = 'ToyTruckServer-ip' var networkSecurityGroupName = 'ToyTruckServer-nsg' var virtualNetworkDefaultSubnetName = 'default' var virtualMachineImageReference = { publisher: 'canonical' offer: '0001-com-ubuntu-server-focal' sku: '20_04-lts-gen2' version: 'latest' } var virtualMachineOSDiskName = 'YOUR-OS-DISK-NAME'
更新
publicIPAddress
资源以引用参数:properties 参数 sku.name
publicIPAddressSkuName
更新
virtualMachine
资源以引用参数和变量:属性 参数或变量 hardwareProfile.vmSize
virtualMachineSizeName
storageProfile.imageReference
virtualMachineImageReference
使用变量名称替换对象的值,包括大括号。storageProfile.osDisk.name
virtualMachineOSDiskName
storageProfile.osDisk.managedDisk.storageAccountType
virtualMachineManagedDiskStorageAccountType
osProfile.adminUsername
virtualMachineAdminUsername
osProfile.adminPassword
在osProfile.adminUsername
下方添加此属性virtualMachineAdminPassword
更新
virtualNetwork
资源以引用参数和变量:属性 参数或变量 addressSpace.addressPrefixes
virtualNetworkAddressPrefix
subnets.name
virtualNetworkDefaultSubnetName
subnets.addressPrefix
virtualNetworkDefaultSubnetAddressPrefix
更新
virtualNetwork
资源的嵌套资源defaultSubnet
:properties 变量 name
virtualNetworkDefaultSubnetName
删除不必要的属性
导出过程中,会将冗余属性添加到多个资源。 使用以下步骤删除不需要的属性。
在
networkSecurityGroup
资源中,删除properties
,因为securityRules
属性为空。在
publicIPAddress
资源中,删除以下属性:ipAddress
属性,因为它由 Azure 自动设置ipTags
属性,因为它为空
在
virtualMachine
资源中,删除以下属性:storageProfile.osDisk.managedDisk.id
属性,因为 Azure 会在部署虚拟机时自动确定该属性重要
如果不删除此属性,模板将无法正确部署。
storageProfile.dataDisks
属性,因为它为空osProfile.secrets
属性,因为它为空osProfile.requireGuestProvisionSignal
属性,因为 Azure 会自动设置此属性
在
virtualNetwork
资源中,删除以下属性:delegations
和virtualNetworkPeerings
属性,因为它们为空。type: 'Microsoft.Network/virtualNetworks/subnets'
的行
在
networkInterface
资源中,删除以下属性:kind
属性从
ipConfigurations
中删除:id
、etag
、type
和privateIPAddress
,因为它由 Azure 自动设置,分配方法为“动态”从
ipConfigurations.properties
:provisioningState
从
publicIPAddress
、name
、properties
、type
和sku
中删除dnsSettings
,因为dnsServers
属性为空
提示
使用自己的模板时,需要确定是否有任何属性应该被删除,正如你在这里所做的那样。
在 Visual Studio Code 中,Bicep 扩展可帮助你设置资源的最小属性。 在资源定义中的等于号后添加空格时,Visual Studio Code 会提示你选择必需属性:
选择“必需属性”时,Visual Studio Code 会使用必需的属性预先填充资源定义。 可以参考“required-properties”来确定转换后的模板中的属性是否都需要存在。
Azure 快速入门模板存储库也有助于完成此任务。 找到一个与你尝试执行的操作大致相同的快速入门模板,然后查看它在资源上设置的属性。
创建参数文件
当前,参数在模板中定义为默认值。 为了使模板在各种环境中都能很好地工作,最好创建一个参数文件,并删除需要为每个环境更改的参数的默认值。
创建名为 main.parameters.production.json 的新文件。
将以下 JSON 粘贴到 main.parameters.production.json 文件中:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualMachineSizeName": { "value": "Standard_D2s_v3" }, "virtualMachineManagedDiskStorageAccountType": { "value": "Premium_LRS" }, "virtualMachineAdminUsername": { "value": "toytruckadmin" }, "virtualNetworkAddressPrefix": { "value": "YOUR-VIRTUAL-NETWORK-ADDRESS-PREFIX" }, "virtualNetworkDefaultSubnetAddressPrefix": { "value": "YOUR-SUBNET-ADDRESS-PREFIX" } } }
更新
virtualNetworkAddressPrefix
和virtualNetworkDefaultSubnetAddressPrefix
参数的值,以匹配引用模板的虚拟网络资源中指定的 IP 地址范围。例如,以下是在参考模板中指定值的方式。 你的 IP 地址可能与此示例中使用的 IP 地址不同。
resource virtualNetworks_ToyTruck_vnet_name_resource 'Microsoft.Network/virtualNetworks@2022-05-01' = { name: virtualNetworks_ToyTruck_vnet_name location: 'westus3' properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: 'default' id: virtualNetworks_ToyTruck_vnet_name_default.id properties: { addressPrefix: '10.0.0.0/24' delegations: [] privateEndpointNetworkPolicies: 'Disabled' privateLinkServiceNetworkPolicies: 'Enabled' } type: 'Microsoft.Network/virtualNetworks/subnets' } ] virtualNetworkPeerings: [] enableDdosProtection: false } }
更新 main.bicep 文件以删除在参数文件中指定的参数的默认值。
virtualMachineSizeName
virtualMachineManagedDiskStorageAccountType
virtualMachineAdminUsername
不更改 location
和 publicIPAddressSkuName
参数的默认值,因为这些值可能在所有环境中都相同。
验证模板
在重构阶段结束时,main.bicep 文件应如以下示例所示:
@description('The location where resources are deployed.') param location string = resourceGroup().location @description('The name of the size of the virtual machine to deploy.') param virtualMachineSizeName string @description('The name of the storage account SKU to use for the virtual machine\'s managed disk.') param virtualMachineManagedDiskStorageAccountType string @description('The administrator username for the virtual machine.') param virtualMachineAdminUsername string @description('The administrator password for the virtual machine.') @secure() param virtualMachineAdminPassword string @description('The name of the SKU of the public IP address to deploy.') param publicIPAddressSkuName string = 'Standard' @description('The virtual network address range.') param virtualNetworkAddressPrefix string @description('The default subnet address range within the virtual network') param virtualNetworkDefaultSubnetAddressPrefix string var virtualNetworkName = 'ToyTruck-vnet' var virtualMachineName = 'ToyTruckServer' var networkInterfaceName = 'YOUR-NETWORK-INTERFACE-NAME' var publicIPAddressName = 'ToyTruckServer-ip' var networkSecurityGroupName = 'ToyTruckServer-nsg' var virtualNetworkDefaultSubnetName = 'default' var virtualMachineImageReference = { publisher: 'canonical' offer: '0001-com-ubuntu-server-focal' sku: '20_04-lts-gen2' version: 'latest' } var virtualMachineOSDiskName = 'YOUR-OS-DISK-NAME' resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2022-05-01' = { name: networkSecurityGroupName location: location } resource publicIPAddress 'Microsoft.Network/publicIPAddresses@2022-05-01' = { name: publicIPAddressName location: location sku: { name: publicIPAddressSkuName tier: 'Regional' } properties: { publicIPAddressVersion: 'IPv4' publicIPAllocationMethod: 'Static' idleTimeoutInMinutes: 4 } } resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = { name: virtualMachineName location: location properties: { hardwareProfile: { vmSize: virtualMachineSizeName } storageProfile: { imageReference: virtualMachineImageReference osDisk: { osType: 'Linux' name: virtualMachineOSDiskName createOption: 'FromImage' caching: 'ReadWrite' managedDisk: { storageAccountType: virtualMachineManagedDiskStorageAccountType } deleteOption: 'Delete' diskSizeGB: 30 } } osProfile: { computerName: virtualMachineName adminUsername: virtualMachineAdminUsername adminPassword: virtualMachineAdminPassword linuxConfiguration: { disablePasswordAuthentication: false provisionVMAgent: true patchSettings: { patchMode: 'ImageDefault' assessmentMode: 'ImageDefault' } enableVMAgentPlatformUpdates: false } allowExtensionOperations: true } networkProfile: { networkInterfaces: [ { id: networkInterface.id properties: { deleteOption: 'Detach' } } ] } diagnosticsProfile: { bootDiagnostics: { enabled: true } } } } resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-05-01' = { name: virtualNetworkName location: location properties: { addressSpace: { addressPrefixes: [ virtualNetworkAddressPrefix ] } subnets: [ { name: virtualNetworkDefaultSubnetName properties: { addressPrefix: virtualNetworkDefaultSubnetAddressPrefix privateEndpointNetworkPolicies: 'Disabled' privateLinkServiceNetworkPolicies: 'Enabled' } } ] enableDdosProtection: false } resource defaultSubnet 'subnets' existing = { name: virtualNetworkDefaultSubnetName } } resource networkInterface 'Microsoft.Network/networkInterfaces@2022-05-01' = { name: networkInterfaceName location: location properties: { ipConfigurations: [ { name: 'ipconfig1' properties: { privateIPAllocationMethod: 'Dynamic' publicIPAddress: { id: publicIPAddress.id } subnet: { id: virtualNetwork::defaultSubnet.id } primary: true privateIPAddressVersion: 'IPv4' } } ] enableAcceleratedNetworking: true enableIPForwarding: false disableTcpStateTracking: false networkSecurityGroup: { id: networkSecurityGroup.id } nicType: 'Standard' } }
main.parameters.production.json 文件应如以下文件所示,不过你可能会列出不同的 IP 地址范围:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualMachineSizeName": { "value": "Standard_D2s_v3" }, "virtualMachineManagedDiskStorageAccountType": { "value": "Premium_LRS" }, "virtualMachineAdminUsername": { "value": "toytruckadmin" }, "virtualNetworkAddressPrefix": { "value": "10.0.0.0/16" }, "virtualNetworkDefaultSubnetAddressPrefix": { "value": "10.0.0.0/24" } } }
选择“查看”>“问题”以显示“问题”窗格。
未显示有任何问题。
提示
当使用自己的模板时,你可能会对要参数化的属性和其他自定义做出不同的选择。 在此模块中,我们提供了可帮助你入门的常规指导,但在决定如何重构自己的 Bicep 文件时,你需要考虑自己的环境以及你希望如何重用模板。