Использование существующей виртуальной сети с управляемыми приложениями Azure

В этой статье описано, как определить управляемое приложение Azure, которое интегрируется с существующей виртуальной сетью в подписке потребителя. Управляемое приложение позволяет потребителю решить, следует ли создать новую виртуальную сеть или использовать существующую. Существующая виртуальная сеть может находиться за пределами управляемой группы ресурсов.

Основной шаблон

Сначала изучим файл mainTemplate.js. Ниже показан полный шаблон для развертывания виртуальной машины и связанных с ней ресурсов. Позже вы подробнее изучите части шаблона, связанные с использованием существующей виртуальной сети.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "metadata": {
        "description": "Deployment location"
      }
    },
    "windowsOSVersion": {
      "type": "string",
      "defaultValue": "2016-Datacenter",
      "allowedValues": [
        "2008-R2-SP1",
        "2012-Datacenter",
        "2012-R2-Datacenter",
        "2016-Nano-Server",
        "2016-Datacenter-with-Containers",
        "2016-Datacenter",
        "2019-Datacenter"
      ],
      "metadata": {
        "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version."
      }
    },
    "vmName": {
      "type": "string",
      "metadata": {
        "title": "VM Name",
        "description": "This is the name of the your VM"
      }
    },
    "adminUsername": {
      "type": "string",
      "defaultValue": "testadmin",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Password for the Virtual Machine."
      }
    },
    "virtualNetworkName": {
      "type": "string",
      "metadata": {
        "description": "New or Existing VNet Name"
      }
    },
    "virtualNetworkNewOrExisting": {
      "type": "string",
      "metadata": {
        "description": "Boolean indicating whether the VNet is new or existing"
      }
    },
    "virtualNetworkAddressPrefix": {
      "type": "string",
      "metadata": {
        "description": "VNet address prefix"
      }
    },
    "virtualNetworkResourceGroup": {
      "type": "string",
      "metadata": {
        "description": "Resource group of the VNet"
      }
    },
    "virtualMachineSize": {
      "type": "string",
      "metadata": {
        "description": "The size of the VM"
      }
    },
    "subnetName": {
      "type": "string",
      "metadata": {
        "description": "New or Existing subnet Name"
      }
    },
    "subnetAddressPrefix": {
      "type": "string",
      "metadata": {
        "description": "Subnet address prefix"
      }
    },
    "baseUrl": {
      "type": "string",
      "defaultValue": "",
      "metadata": {
        "artifactsBaseUrl": "",
        "description": "URL to acquire other templates"
      }
    }
  },
  "variables": {
    "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sawinvm')]",
    "publicIPAddressName": "[concat(uniqueString(resourceGroup().id),'IP')]",
    "vmName": "[parameters('vmName')]",
    "nicName": "[concat(parameters('vmName'),'Nic')]",
    "vnetId": {
      "new": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]",
      "existing": "[resourceId(parameters('virtualNetworkResourceGroup'),'Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]"
    },
    "subnetId": "[concat(variables('vnetId')[parameters('virtualNetworkNewOrExisting')],'/subnets/',parameters('subnetName'))]",
    "publicIPAddressType": "Dynamic"
  },
  "resources": [
    {
      "condition": "[equals(parameters('virtualNetworkNewOrExisting'),'new')]",
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2021-02-01",
      "name": "[parameters('virtualNetworkName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[parameters('virtualNetworkAddressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[parameters('subnetName')]",
            "properties": {
              "addressPrefix": "[parameters('subnetAddressPrefix')]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('publicIPAddressName')]",
      "apiVersion": "2021-02-01",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAllocationMethod": "[variables('publicIPAddressType')]"
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[variables('nicName')]",
      "apiVersion": "2021-02-01",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
              },
              "subnet": {
                "id": "[variables('subnetId')]"
              }
            }
          }
        ],
        "enableIPForwarding": true
      },
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]"
      ]
    },
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-04-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2021-04-01",
      "name": "[variables('vmName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
        "[resourceId('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('virtualMachineSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "[parameters('windowsOSVersion')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          },
          "dataDisks": [
            {
              "diskSizeGB": 1023,
              "lun": 0,
              "createOption": "Empty"
            }
          ]
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))).primaryEndpoints.blob]"
          }
        }
      }
    }
  ]
}

Обратите внимание, что виртуальная сеть условно развернута. Потребитель передает значение параметра, которое указывает, следует ли создать новую или использовать существующую виртуальную сеть. Если потребитель выбирает новую виртуальную сеть, ресурс развертывается. Иначе ресурс пропускается во время развертывания.

{
  "condition": "[equals(parameters('virtualNetworkNewOrExisting'),'new')]",
  "type": "Microsoft.Network/virtualNetworks",
  "apiVersion": "2021-02-01",
  "name": "[parameters('virtualNetworkName')]",
  "location": "[parameters('location')]",
  "properties": {
    "addressSpace": {
      "addressPrefixes": [
        "[parameters('virtualNetworkAddressPrefix')]"
      ]
    },
    "subnets": [
      {
        "name": "[parameters('subnetName')]",
        "properties": {
          "addressPrefix": "[parameters('subnetAddressPrefix')]"
        }
      }
    ]
  }
},

Переменная для идентификатора виртуальной сети имеет два свойства. Одно свойство возвращает идентификатор ресурса при развертывании новой виртуальной сети. Другое свойство возвращает идентификатор ресурса при использовании существующей виртуальной сети. Идентификатор ресурса для существующей виртуальной сети включает имя группы ресурсов, содержащей виртуальную сеть.

Идентификатор подсети создается на основе значения для идентификатора виртуальной сети. Он использует значение, совпадающее с выбором получателей.

"variables": {
  "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sawinvm')]",
  "publicIPAddressName": "[concat(uniqueString(resourceGroup().id),'IP')]",
  "vmName": "[parameters('vmName')]",
  "nicName": "[concat(parameters('vmName'),'Nic')]",
  "vnetId": {
    "new": "[resourceId('Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]",
    "existing": "[resourceId(parameters('virtualNetworkResourceGroup'),'Microsoft.Network/virtualNetworks',parameters('virtualNetworkName'))]"
  },
  "subnetId": "[concat(variables('vnetId')[parameters('virtualNetworkNewOrExisting')],'/subnets/',parameters('subnetName'))]",
  "publicIPAddressType": "Dynamic"
},

Для сетевого интерфейса задается переменная с идентификатором подсети.

{
  "type": "Microsoft.Network/networkInterfaces",
  "name": "[variables('nicName')]",
  "apiVersion": "2021-02-01",
  "location": "[parameters('location')]",
  "properties": {
    "ipConfigurations": [
      {
        "name": "ipconfig1",
        "properties": {
          "privateIPAllocationMethod": "Dynamic",
          "publicIPAddress": {
            "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
          },
          "subnet": {
            "id": "[variables('subnetId')]"
          }
        }
      }
    ],
    "enableIPForwarding": true
  },

Определение ИП

Теперь давайте взглянем на файл createUiDefinition.json. Полный файл

{
  "handler": "Microsoft.Azure.CreateUIDef",
  "version": "0.1.2-preview",
  "parameters": {
    "basics": [],
    "steps": [
      {
        "name": "deploymentDetails",
        "label": "Deployment Details",
        "subLabel": {
          "preValidation": "Required",
          "postValidation": "Done"
        },
        "bladeTitle": "Deployment Details",
        "elements": [
          {
            "name": "virtualMachine",
            "type": "Microsoft.Common.Section",
            "elements": [
              {
                "name": "vmName",
                "type": "Microsoft.Common.TextBox",
                "label": "VM Name",
                "toolTip": "Name of your virtual machine",
                "constraints": {
                  "required": true
                }
              },
              {
                "name": "vmPassword",
                "type": "Microsoft.Compute.CredentialsCombo",
                "label": {
                  "password": "Password",
                  "confirmPassword": "Confirm password"
                },
                "toolTip": {
                  "password": ""
                },
                "constraints": {
                  "required": true,
                  "customPasswordRegex": "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{12,}$",
                  "customValidationMessage": "The password must be alphanumeric, contain at least 12 characters, and have at least 1 letter and 1 number."
                },
                "options": {
                  "hideConfirmation": false
                },
                "osPlatform": "Windows",
                "visible": true
              }
            ],
            "visible": true
          },
          {
            "name": "vnet",
            "type": "Microsoft.Network.VirtualNetworkCombo",
            "label": {
              "virtualNetwork": "Virtual Network",
              "subnets": "Subnets"
            },
            "defaultValue": {
              "name": "vmx-vnet",
              "addressPrefixSize": "/16"
            },
            "constraints": {
              "minAddressPrefixSize": "/24"
            },
            "subnets": {
              "subnet1": {
                "label": "Subnet",
                "defaultValue": {
                  "name": "vmx-subnet",
                  "addressPrefixSize": "/24"
                },
                "constraints": {
                  "minAddressPrefixSize": "/29",
                  "minAddressCount": 8,
                  "requireContiguousAddresses": true
                }
              }
            }
          },
          {
            "name": "VMSize",
            "type": "Microsoft.Compute.SizeSelector",
            "label": "VM size",
            "toolTip": "The size of virtual machine for VM.",
            "recommendedSizes": [
              "Standard_D2_v2",
              "Standard_D2_v3"
            ],
            "constraints": {
              "allowedSizes": [
                "Standard_D2_v2",
                "Standard_D2_v3"
              ],
              "excludedSizes": []
            },
            "osPlatform": "Windows",
            "imageReference": {
              "publisher": "MicrosoftWindowsServer",
              "offer": "WindowsServer",
              "sku": "2012-R2-Datacenter"
            }
          }
        ]
      },
      {
        "name": "identityDetails",
        "label": "Managed Identity Details",
        "subLabel": {
          "preValidation": "Required",
          "postValidation": "Done"
        },
        "bladeTitle": "Managed Identity Details",
        "elements": [
          {
            "name": "identity",
            "type": "Microsoft.ManagedIdentity.IdentitySelector",
            "label": "Managed Identity Configuration",
            "toolTip": {
              "systemAssignedIdentity": "Enable system assigned identity to grant the resource access to other existing resources.",
              "userAssignedIdentity": "Add user assigned identities to grant the resource access to other existing resources."
            },
            "defaultValue": {
              "systemAssignedIdentity": "Off"
            },
            "options": {
              "hideSystemAssignedIdentity": false,
              "hideUserAssignedIdentity": false
            },
            "visible": true
          }
        ]
      }
    ],
    "outputs": {
      "location": "[location()]",
      "vmName": "[steps('deploymentDetails').virtualMachine.vmName]",
      "adminPassword": "[steps('deploymentDetails').virtualMachine.vmPassword.password]",
      "virtualNetworkName": "[steps('deploymentDetails').vnet.name]",
      "virtualNetworkNewOrExisting": "[steps('deploymentDetails').vnet.newOrExisting]",
      "virtualNetworkAddressPrefix": "[first(steps('deploymentDetails').vnet.addressPrefixes)]",
      "virtualNetworkResourceGroup": "[steps('deploymentDetails').vnet.resourceGroup]",
      "virtualMachineSize": "[steps('deploymentDetails').VMSize]",
      "subnetName": "[steps('deploymentDetails').vnet.subnets.subnet1.name]",
      "subnetAddressPrefix": "[steps('deploymentDetails').vnet.subnets.subnet1.addressPrefix]",
      "managedIdentity": "[steps('identityDetails').identity]"
    }
  }
}

Файл содержит элемент виртуальной сети.

{
  "name": "vnet",
  "type": "Microsoft.Network.VirtualNetworkCombo",
  "label": {
    "virtualNetwork": "Virtual Network",
    "subnets": "Subnets"
  },
  "defaultValue": {
    "name": "vmx-vnet",
    "addressPrefixSize": "/16"
  },
  "constraints": {
    "minAddressPrefixSize": "/24"
  },
  "subnets": {
    "subnet1": {
      "label": "Subnet",
      "defaultValue": {
        "name": "vmx-subnet",
        "addressPrefixSize": "/24"
      },
      "constraints": {
        "minAddressPrefixSize": "/29",
        "minAddressCount": 8,
        "requireContiguousAddresses": true
      }
    }
  }
},

Этот элемент позволяет потребителю выбрать новую или существующую виртуальную сеть.

                            Новая или имеющаяся виртуальная сеть

В выходные данные включается значение, указывающее, выбрал ли потребитель новую или существующую виртуальную сеть. Также существует управляемое значение идентификатора.

Примечание.

Выходное значение для управляемого удостоверения должно называться managedIdentity.

"outputs": {
  "location": "[location()]",
  "vmName": "[steps('deploymentDetails').virtualMachine.vmName]",
  "adminPassword": "[steps('deploymentDetails').virtualMachine.vmPassword.password]",
  "virtualNetworkName": "[steps('deploymentDetails').vnet.name]",
  "virtualNetworkNewOrExisting": "[steps('deploymentDetails').vnet.newOrExisting]",
  "virtualNetworkAddressPrefix": "[first(steps('deploymentDetails').vnet.addressPrefixes)]",
  "virtualNetworkResourceGroup": "[steps('deploymentDetails').vnet.resourceGroup]",
  "virtualMachineSize": "[steps('deploymentDetails').VMSize]",
  "subnetName": "[steps('deploymentDetails').vnet.subnets.subnet1.name]",
  "subnetAddressPrefix": "[steps('deploymentDetails').vnet.subnets.subnet1.addressPrefix]",
  "managedIdentity": "[steps('identityDetails').identity]"
}

Следующие шаги

Дополнительные сведения о создании файла определения пользовательского интерфейса см. в статье CreateUiDefinition.jsоn при создании управляемого приложения Azure.