Создание виртуальных машин в масштабируемом наборе с помощью шаблона ARM
В этой статье описывается использование шаблона ARM для создания масштабируемого набора виртуальных машин.
Шаблон Azure Resource Manager — это файл нотации объектов JavaScript (JSON), который определяет инфраструктуру и конфигурацию проекта. В шаблоне используется декларативный синтаксис. Вы описываете предполагаемое развертывание без написания последовательности команд программирования для создания развертывания.
Если среда соответствует предварительным требованиям и вы знакомы с использованием шаблонов ARM, нажмите кнопку Развертывание в Azure. Шаблон откроется на портале Azure.
Необходимые компоненты
Если у вас нет подписки Azure, создайте бесплатную учетную запись, прежде чем приступить к работе.
Шаблон ARM
Шаблон Azure Resource Manager — это файл нотации объектов JavaScript (JSON), который определяет инфраструктуру и конфигурацию проекта. В шаблоне используется декларативный синтаксис. Вы описываете предполагаемое развертывание без написания последовательности команд программирования для создания развертывания.
Шаблоны ARM позволяют развертывать группы связанных ресурсов. В одном шаблоне можно создать масштабируемый набор виртуальных машин, установить приложения и настроить правила автомасштабирования. Вы можете повторно использовать этот шаблон, применив переменные и параметры, чтобы обновить существующие или создать дополнительные масштабируемые наборы. Шаблоны можно развернуть с помощью портала Azure, Azure CLI или Azure PowerShell либо же на основе конвейеров непрерывной интеграции и непрерывной поставки (CI/CD).
Изучение шаблона
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources"
}
},
"vmSku": {
"type": "string",
"defaultValue": "Standard_D2s_v3",
"metadata": {
"description": "Size of VMs in the VM Scale Set."
}
},
"vmssName": {
"type": "string",
"metadata": {
"description": "String used as a base for naming resources (9 characters or less). A hash is prepended to this string for some resources, and resource-specific information is appended."
}
},
"instanceCount": {
"type": "int",
"defaultValue": 1,
"minValue": 1,
"maxValue": 100,
"metadata": {
"description": "Number of VM instances (100 or less)."
}
},
"adminUsername": {
"type": "string",
"metadata": {
"description": "Admin username on all VMs."
}
},
"authenticationType": {
"type": "string",
"defaultValue": "sshPublicKey",
"allowedValues": [
"sshPublicKey",
"password"
],
"metadata": {
"description": "Type of authentication to use on the Virtual Machine. SSH key is recommended."
}
},
"adminPasswordOrKey": {
"type": "securestring",
"metadata": {
"description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
}
},
"securityType": {
"type": "string",
"defaultValue": "TrustedLaunch",
"allowedValues": [
"Standard",
"TrustedLaunch"
],
"metadata": {
"description": "Security Type of the Virtual Machine."
}
},
"_artifactsLocation": {
"type": "string",
"defaultValue": "[deployment().properties.templatelink.uri]",
"metadata": {
"description": "The base URI where artifacts required by this template are located"
}
},
"_artifactsLocationSasToken": {
"type": "securestring",
"defaultValue": "",
"metadata": {
"description": "The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated"
}
}
},
"variables": {
"addressPrefix": "10.0.0.0/16",
"subnetPrefix": "10.0.0.0/24",
"networkApiVersion": "2020-11-01",
"virtualNetworkName": "[concat(parameters('vmssName'), 'vnet')]",
"publicIPAddressName": "[concat(parameters('vmssName'), 'pip')]",
"subnetName": "[concat(parameters('vmssName'), 'subnet')]",
"loadBalancerName": "[concat(parameters('vmssName'), 'lb')]",
"publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
"networkSecurityGroupName": "[concat(parameters('vmssName'), 'nsg')]",
"bePoolName": "[concat(parameters('vmssName'), 'bepool')]",
"lbRuleName": "[concat(parameters('vmssName'), 'lbrule')]",
"lbProbeName": "[concat(parameters('vmssName'), 'lbprobe')]",
"bePoolConfigID": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadBalancerName'),variables('bePoolName'))]",
"lbProbeID": "[resourceId('Microsoft.Network/loadBalancers/probes', variables('loadBalancerName'),variables('lbProbeName'))]",
"nicName": "[concat(parameters('vmssName'), 'nic')]",
"ipConfigName": "[concat(parameters('vmssName'), 'ipconfig')]",
"frontEndIPConfigID": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', variables('loadBalancerName'),'loadBalancerFrontEnd')]",
"osType": {
"publisher": "Canonical",
"offer": "0001-com-ubuntu-server-focal",
"sku": "20_04-lts-gen2",
"version": "latest"
},
"imageReference": "[variables('osType')]",
"securityProfileJson": {
"uefiSettings": {
"secureBootEnabled": true,
"vTpmEnabled": true
},
"securityType": "[parameters('securityType')]"
},
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
"keyData": "[parameters('adminPasswordOrKey')]"
}
]
}
}
},
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2023-04-01",
"name": "[variables('networkSecurityGroupName')]",
"location": "[parameters('location')]",
"properties": {
"securityRules": [
{
"name": "AllowPort9000",
"properties": {
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "9000",
"sourceAddressPrefix": "Internet",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2023-04-01",
"name": "[variables('virtualNetworkName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}
}
}
]
}
},
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2023-04-01",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard"
},
"properties": {
"publicIPAllocationMethod": "Static",
"dnsSettings": {
"domainNameLabel": "[parameters('vmssName')]"
}
}
},
{
"type": "Microsoft.Network/loadBalancers",
"apiVersion": "2023-04-01",
"name": "[variables('loadBalancerName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard"
},
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
],
"properties": {
"frontendIPConfigurations": [
{
"name": "LoadBalancerFrontEnd",
"properties": {
"publicIPAddress": {
"id": "[variables('publicIPAddressID')]"
}
}
}
],
"backendAddressPools": [
{
"name": "[variables('bePoolName')]"
}
],
"probes": [
{
"name": "[variables('lbProbeName')]",
"properties": {
"port": 9000,
"protocol": "Tcp",
"numberOfProbes": 2,
"intervalInSeconds": 5
}
}
],
"loadBalancingRules": [
{
"name": "[variables('lbRuleName')]",
"properties": {
"frontendIPConfiguration": {
"id": "[variables('frontEndIPConfigID')]"
},
"backendAddressPool": {
"id": "[variables('bePoolConfigID')]"
},
"probe": {
"id": "[variables('lbProbeID')]"
},
"loadDistribution": "Default",
"backendPort": 9000,
"frontendPort": 9000,
"protocol": "Tcp",
"idleTimeoutInMinutes": 4,
"enableFloatingIP": false,
"enableTcpReset": false,
"disableOutboundSnat": false
}
}
]
}
},
{
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2023-09-01",
"name": "[parameters('vmssName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('vmSku')]",
"tier": "Standard",
"capacity": "[parameters('instanceCount')]"
},
"dependsOn": [
"[resourceId('Microsoft.Network/loadBalancers', variables('loadBalancerName'))]",
"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
],
"properties": {
"orchestrationMode": "Flexible",
"platformFaultDomainCount": 1,
"singlePlacementGroup": false,
"virtualMachineProfile": {
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"caching": "ReadWrite"
},
"imageReference": "[variables('imageReference')]"
},
"osProfile": {
"computerNamePrefix": "[parameters('vmssName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPasswordOrKey')]",
"linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]"
},
"securityProfile": "[if(equals(parameters('securityType'), 'TrustedLaunch'), variables('securityProfileJson'), null())]",
"networkProfile": {
"networkApiVersion": "[variables('networkApiVersion')]",
"networkInterfaceConfigurations": [
{
"name": "[variables('nicName')]",
"properties": {
"primary": true,
"ipConfigurations": [
{
"name": "[variables('ipConfigName')]",
"properties": {
"primary": true,
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworkName'), variables('subnetName'))]"
},
"loadBalancerBackendAddressPools": [
{
"id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadBalancerName'), variables('bePoolName'))]"
}
]
}
}
]
}
}
]
},
"extensionProfile": {
"extensions": [
{
"name": "lapextension",
"properties": {
"publisher": "Microsoft.Azure.Extensions",
"type": "CustomScript",
"typeHandlerVersion": "2.0",
"autoUpgradeMinorVersion": true,
"enableAutomaticUpgrade": true,
"settings": {
"fileUris": [
"[uri(parameters('_artifactsLocation'), concat('installserver.sh', parameters('_artifactsLocationSasToken')))]",
"[uri(parameters('_artifactsLocation'), concat('workserver.py', parameters('_artifactsLocationSasToken')))]"
],
"commandToExecute": "bash installserver.sh"
}
}
}
]
}
}
}
},
{
"type": "Microsoft.Insights/autoscaleSettings",
"apiVersion": "2022-10-01",
"name": "[concat(parameters('vmssName'), '-autoscalehost')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('vmSSName'))]"
],
"properties": {
"name": "[concat(parameters('vmssName'), '-autoscalehost')]",
"targetResourceUri": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('vmSSName'))]",
"enabled": true,
"profiles": [
{
"name": "Profile1",
"capacity": {
"minimum": "1",
"maximum": "10",
"default": "1"
},
"rules": [
{
"metricTrigger": {
"metricName": "Percentage CPU",
"metricResourceUri": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('vmSSName'))]",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT5M",
"timeAggregation": "Average",
"operator": "GreaterThan",
"threshold": 60
},
"scaleAction": {
"direction": "Increase",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT1M"
}
},
{
"metricTrigger": {
"metricName": "Percentage CPU",
"metricResourceUri": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('vmSSName'))]",
"timeGrain": "PT1M",
"statistic": "Average",
"timeWindow": "PT5M",
"timeAggregation": "Average",
"operator": "LessThan",
"threshold": 30
},
"scaleAction": {
"direction": "Decrease",
"type": "ChangeCount",
"value": "1",
"cooldown": "PT1M"
}
}
]
}
]
}
}
]
}
В шаблоне определены следующие ресурсы:
- Microsoft.Network/virtualNetworks;
- Microsoft.Network/publicIPAddresses
- Microsoft.Network/loadBalancers;
- Microsoft.Compute/virtualMachineScaleSets;
- Microsoft.Insights/autoscaleSettings
- Microsoft.Network/networkSecurityGroups;
Определение масштабируемого набора
Чтобы создать масштабируемый набор с помощью шаблона, определите необходимые ресурсы. Основные части типа ресурсов масштабируемого набора виртуальных машин:
Свойство | Описание свойства | Пример значения в шаблоне |
---|---|---|
type | Создаваемый тип ресурса Azure | Microsoft.Compute/virtualMachineScaleSets; |
name | Имя масштабируемого набора | myScaleSet |
расположение | Расположение для создания масштабируемого набора | Восточная часть США |
sku.name | Размер виртуальной машины для каждого экземпляра в масштабируемом наборе | Standard_A1 |
sku.capacity | Количество экземпляров виртуальных машин, которое требуется изначально создать | 2 |
imageReference | Платформа или пользовательский образ, используемые для экземпляров виртуальных машин | Сервер Canonical Ubuntu 16.04-LTS |
osProfile.computerNamePrefix | Префикс имени для каждого экземпляра виртуальной машины | myvmss |
osProfile.adminUsername | Имя пользователя для каждого экземпляра виртуальной машины | azureuser |
osProfile.adminPassword | Пароль для каждого экземпляра виртуальной машины | P@ssw0rd! |
Чтобы настроить шаблон масштабируемого набора, вы можете изменить размер виртуальной машины или начальную емкость. Еще один вариант — использовать другую платформу или пользовательский образ.
Добавление примера приложения
Для проверки масштабируемого набора установите базовое веб-приложение. Когда вы развертываете масштабируемый набор, расширения виртуальных машин могут предусматривать задачи автоматизации и настройки после развертывания, например задачи установки приложения. Сценарии можно скачать из службы хранилища Azure или GitHub или передать на портал Azure во время выполнения расширения. Чтобы применить расширение к масштабируемому набору, добавьте раздел extensionProfile в предыдущий пример ресурса. Как правило, профиль расширения определяет следующие свойства:
- тип расширения;
- издатель расширения;
- версия расширения;
- расположение скриптов настройки или установки;
- команды для выполнения на экземплярах виртуальных машин.
В шаблоне используется настраиваемое расширение скриптов для установки Bottle, веб-платформы Python и простого HTTP-сервера.
Два скрипта определены в файлах fileUris - installserver.sh и workserver.py. Эти файлы скачиваются из GitHub, затем commandToExecute выполняет bash installserver.sh
для установки и настройки приложения.
Развертывание шаблона
Вы также можете развернуть шаблон Resource Manager с помощью Azure CLI:
# Create a resource group
az group create --name myResourceGroup --location EastUS
# Deploy template into resource group
az deployment group create -g myResourceGroup -f azuredeploy.json --parameters _artifactsLocation=https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/application-workloads/python/vmss-bottle-autoscale/azuredeploy.json
В ответ на запросы предоставьте имя масштабируемого набора, число экземпляров и учетные данные администратора для экземпляров виртуальных машин. Создание масштабируемого набора и вспомогательных ресурсов занимает несколько минут.
Проверка развертывания
Чтобы увидеть, как работает масштабируемый набор, откройте пример веб-приложения в браузере. Получите общедоступный IP-адрес подсистемы балансировки нагрузки с помощью команды az network public-ip list:
az network public-ip list \
--resource-group myResourceGroup \
--query [*].ipAddress -o tsv
Введите в браузер общедоступный IP-адрес подсистемы балансировки нагрузки в формате http://publicIpAddress:9000/do_work. Подсистема балансировки нагрузки передаст запрос на один из экземпляров виртуальной машины, как показано в следующем примере:
Очистка ресурсов
Вы можете удалить ненужную группу ресурсов, масштабируемый набор и все связанные ресурсы с помощью команды az group delete, как показано ниже. При использовании параметра --no-wait
управление возвращается в командную строку без ожидания завершения операции. Параметр --yes
подтверждает, что вы хотите удалить ресурсы без дополнительного запроса.
az group delete --name myResourceGroup --yes --no-wait