練習 - 重構 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
網路介面 networkInterfaces_toytruckserver890_name_resource
networkInterface
移除多餘的子網路資源
虛擬網路的子網路目前定義兩次。 在 virtualNetwork
資源中定義一次,並再次定義為其本身名為 defaultSubnet
的子資源。 定義子網路兩次沒有意義。
刪除
defaultSubnet
資源。請注意,
networkInterface
資源現在出現問題,因為參考預設子網路的資源識別碼:更新
virtualNetwork
資源以包含對子網路的existing
參考。 若您新增existing
參考,您可以在 Bicep 程式碼中再次參考該子網路,而不需再次定義:resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-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
資源更新為參考子網路的資源識別碼:resource networkInterface 'Microsoft.Network/networkInterfaces@2024-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
資源以參考參數:屬性 參數 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
:屬性 變數 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 會提示您選取 required-properties:
選取 [required-properties] 時,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@2024-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@2024-05-01' = { name: networkSecurityGroupName location: location } resource publicIPAddress 'Microsoft.Network/publicIPAddresses@2024-05-01' = { name: publicIPAddressName location: location sku: { name: publicIPAddressSkuName tier: 'Regional' } properties: { publicIPAddressVersion: 'IPv4' publicIPAllocationMethod: 'Static' idleTimeoutInMinutes: 4 } } resource virtualMachine 'Microsoft.Compute/virtualMachines@2024-07-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@2024-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@2024-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' } }
儘管列出的 IP 位址範圍可能不同,但是 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": "10.0.0.0/16" }, "virtualNetworkDefaultSubnetAddressPrefix": { "value": "10.0.0.0/24" } } }
選取 [檢視] > [問題] 來顯示 [問題] 窗格。
未指出任何問題。
提示
使用您自己的範本時,對於要參數化的屬性和其他自訂,您可能有不同的選擇。 在整個本課程模組中,我們提供一般指引來協助您開始使用,但在決定如何重構您自己的 Bicep 檔案時,您必須考慮自己的環境及如何重複使用範本。