Изменяем и удаляем Azure VMs, используя PowerShell

Автор оригинала: Adam Bertram
  • Перевод
  • Tutorial
С помощью PowerShell инженеры и IT-администраторы успешно автоматизируют различные задачи при работе не только с on-premises, но и с облачными инфраструктурами, в частности, с Azure. Работать через PowerShell в ряде случаев гораздо удобнее и быстрее, чем через Azure portal. Благодаря кросс-платформенности PowerShell можно использовать для любых ОС.

Неважно, работаете ли вы с Ubuntu, Red Hat или Windows — PowerShell поможет контролировать облачные ресурсы. Используя модуль Azure PowerShell, к примеру, можно задавать любые свойства виртуальных машин.

В этой статье мы рассмотрим, как можно использовать PowerShell, чтобы изменить размер ВМ в облаке Azure, а также чтобы удалить ВМ и ассоциированные с ней объекты.



Важно! Не забудьте протереть руки санитайзером подготовиться к работе:

  • Вам понадобится модуль Azure PowerShell Module — его можно загрузить из PowerShell Gallery командой Install-Module Az.
  • Нужно аутентифицироваться в облаке Azure, где крутится виртуальная машина, выполнив команду Connect-AzAccount.

Для начала создадим скрипт, который ресайзит Azure VM. Откроем VS Code и сохраним новый PowerShell скрипт под названием Resize-AzVirtualMachine.ps1 — в него мы по ходу примера будем добавлять куски кода.

Запрашиваем имеющиеся размеры ВМ


До того, как поменять размер ВМ, нужно узнать, какие вообще имеются допустимые размеры для виртуальных машин в облаке Azure. Для этого надо выполнить команду Get-AzVMSize.

Итак, для виртуальной машины devvm01 из ресурсной группы dev запрашиваем всевозможные допустимые размеры:

Get-AzVMSize -ResourceGroupName dev -VMName devvm01

(В реальных задачах, естественно, вместо ResourceGroupName=dev и VMName=devvm01 вы будете указывать свои значения этих параметров.)

Команда вернет примерно такой перечень:



Это все возможные варианты размеров, которые можно задать для данной виртуальной машины.

Ресайзим машину


Для примера мы сделаем ресайз на новый размер Standard_B1ls — он на первом месте в списке выше. (В реальных задачах, разумеется, вы выбираете любой нужный вам размер.)

  1. Сначала с помощью команды Get-AzVM получаем сведения о нашем объекте (виртуальной машине), сохраняя их в переменную $virtualMachine:

    $virtualMachine = Get-AzVM -ResourceGroupName dev -VMName devvm01
  2. Затем у этого объекта берем свойство .HardwareProfile.VmSize и устанавливаем нужное новое значение:

    $virtualMachine.HardwareProfile.VmSize = "Standard_B1ls"
  3. И теперь просто выполняем команду обновления ВМ — Update-AzVm:

    Update-AzVM -VM devvm01 -ResourceGroupName dev
  4. Убеждаемся, что всё прошло успешно — для этого опять же запрашиваем информацию о нашем объекте и смотрим на свойство $virtualMachine.HardwareProfile:

    $virtualMachine = Get-AzVM -ResourceGroupName dev -VMName devvm01
    $virtualMachine.HardwareProfile

Если там видим Standard_B1ls — значит, всё в порядке, размер машины изменен. Можно пойти дальше и развить успех — заресайзить сразу несколько ВМ, используя массив.

А что насчет удаления ВМ в Azure?


С удалением не всё так просто и прямолинейно, как может показаться. Ведь надо удалить еще ряд ресурсов, ассоциированных с этой машиной, в том числе:

  • Сторадж-контейнеры для диагностики загрузки (Boot diagnostics storage containers)
  • Сетевые интерфейсы
  • Публичные IP адреса
  • Системный диск и blob, где хранится его статус
  • Диски с данными (data disks)

Посему мы создадим функцию и назовем ее Remove-AzrVirtualMachine — и она будет удалять не только Azure VM, но и все вышеперечисленное.

Идём стандартным путем и сначала получаем наш объект (ВМ) с помощью команды Get-AzVm. Для примера пусть это будет машина WINSRV19 из ресурсной группы MyTestVMs.

Сохраним этот объект вместе со всеми его свойствами в переменную $vm:

$vm = Get-AzVm -Name WINSRV19 -ResourceGroupName MyTestVMs

Удаляем контейнер с файлами диагностики загрузки


При создании ВМ в Azure пользователю предлагается также создать и контейнер для хранения диагностики загрузки (boot diagnostics container), чтобы при неполадках с загрузкой было к чему обратиться на предмет траблшутинга. Однако при удалении ВМ этот контейнер остается продолжать свое теперь бесцельное существование. Исправим эту ситуацию.

  1. Сперва выясним, какому сторадж-аккаунту принадлежит этот контейнер — для этого нам нужно разыскать свойство storageUri в недрах объекта DiagnosticsProfile нашей ВМ. Для этого я использую вот такое регулярное выражение:

    $diagSa = [regex]::match($vm.DiagnosticsProfile.bootDiagnostics.storageUri, '^http[s]?://(.+?)\\.').groups[1].value
  2. Теперь надо узнать имя контейнера, а для этого нужно получить VM ID с помощью команды Get-AzResource:

    
    if ($vm.Name.Length -gt 9) {
        $i = 9
    } else {
        $i = $vm.Name.Length - 1
    }
     
    $azResourceParams = @{
        'ResourceName' = WINSRV
        'ResourceType' = 'Microsoft.Compute/virtualMachines'
        'ResourceGroupName' = MyTestVMs
    }
     
    $vmResource = Get-AzResource @azResourceParams
    $vmId = $vmResource.Properties.VmId
    $diagContainerName = ('bootdiagnostics-{0}-{1}' -f $vm.Name.ToLower().Substring(0, $i), $vmId)
    
  3. Далее получаем имя ресурсной группы, к которой принадлежит контейнер:

    $diagSaRg = (Get-AzStorageAccount | where { $_.StorageAccountName -eq $diagSa }).ResourceGroupName
  4. И теперь у нас есть все необходимое, чтобы удалить контейнер командой Remove-AzStorageContainer:

    $saParams = @{
        'ResourceGroupName' = $diagSaRg
        'Name' = $diagSa
    }
     
    Get-AzStorageAccount @saParams | Get-AzStorageContainer | where { $_.Name-eq $diagContainerName } | Remove-AzStorageContainer -Force

Удаляем ВМ


Теперь удалим собственно виртуальную машину, благо мы уже создали переменную $vm для соответствующего объекта. Что ж, запустим команду Remove-AzVm:

$null = $vm | Remove-AzVM -Force

Удаляем сетевой интерфейс и публичный IP-адрес


У нашей ВМ остались один (или даже несколько) сетевых интерфейсов (NICs) — чтобы удалить их за ненужностью, пройдемся по свойству NetworkInterfaces нашего объекта VM и удалим NIC командой Remove-AzNetworkInterface. На случай, если сетевых интерфейсов более одного, используем цикл. Заодно для каждого NIC проверим свойство IpConfiguration на предмет того, есть ли у интерфейса публичный IP адрес. Буде таковой обнаружится, удалим его командой Remove-AzPublicIpAddress.

Вот пример как раз такого кода, где мы в цикле просматриваем все NICs, удаляем их, проверяем, имеется ли публичный IP. Если есть, то парсим свойство PublicIpAddress, достаем по ID имя соответствующего ресурса и удаляем его:


foreach($nicUri in $vm.NetworkProfile.NetworkInterfaces.Id) {
    $nic = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $nicUri.Split('/')[-1]
    Remove-AzNetworkInterface -Name $nic.Name -ResourceGroupName $vm.ResourceGroupName -Force

    foreach($ipConfig in $nic.IpConfigurations) {
        if($ipConfig.PublicIpAddress -ne $null) {
            Remove-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $ipConfig.PublicIpAddress.Id.Split('/')[-1] -Force
        }
    }
}

Удаляем системный диск


Диск ОС представляет собой blob, для удаления коего имеется команда Remove-AzStorageBlob — но перед тем, как ее выполнять, нужно будет задать требуемые значения ее параметрам. Для этого, в частности, нужно получить имя сторадж-контейнера, содержащего системный диск, и потом уже передать его данной команде вместе с соответствующим сторадж-аккаунтом.

$osDiskUri = $vm.StorageProfile.OSDisk.Vhd.Uri
$osDiskContainerName = $osDiskUri.Split('/')[-2]
$osDiskStorageAcct = Get-AzStorageAccount | where { $_.StorageAccountName -eq $osDiskUri.Split('/')[2].Split('.')[0] }
$osDiskStorageAcct | Remove-AzStorageBlob -Container $osDiskContainerName -Blob $osDiskUri.Split('/')[-1]

Удаляем Blob статуса системного диска


Для этого, как вы уже наверняка догадались, мы берем сторадж-контейнер, в котором хранится данный диск, и, подразумевая, что blob в конце содержит status, передаем соответствующие параметры команде удаления Remove-AzStorageBlob:

$osDiskStorageAcct | Get-AzStorageBlob -Container $osDiskContainerName -Blob "$($vm.Name)*.status" | Remove-AzStorageBlob

И, наконец, удаляем диски с данными


У нашей ВМ могли оставаться диски с данными, которые были к ней приаттачены. Если в них нет необходимости, удалим и их тоже. Сначала распарсим StorageProfile нашей ВМ и найдем свойство Uri. Если дисков несколько, организуем цикл по URI. Для каждого URI найдем соответствующий сторадж-аккаунт с помощью Get-AzStorageAccount. Затем распарсим storage URI, чтобы вытащить нужное имя blob-a и передать его команде удаления Remove-AzStorageBlob вместе со сторадж-аккаунтом. Вот как это будет выглядеть в коде:

if ($vm.DataDiskNames.Count -gt 0) {
    foreach ($uri in $vm.StorageProfile.DataDisks.Vhd.Uri) {
        $dataDiskStorageAcct = Get-AzStorageAccount -Name $uri.Split('/')[2].Split('.')[0]
        $dataDiskStorageAcct | Remove-AzStorageBlob -Container $uri.Split('/')[-2] -Blob $uri.Split('/')[-1]
    }
}

И вот “мы добрались до счастливого конца!” Теперь из всех этих фрагментов надо собрать единое целое. Добрый автор Адам Бертрам пошел навстречу пользователям и сделал это сам. Вот ссылочка на итоговый скрипт под названием Remove-AzrVirtualMachine.ps1:

GitHub

Надеюсь, что эти практические советы пригодятся вам, чтобы сэкономить силы, время и средства при работе с Azure VMs.
Veeam Software
Продукты для резервного копирования информации

Комментарии 3

    0
    Вопрос автору — сколько у Вас регионов и сколько Vms?
    У нас powershell вообще не взлетел — перфоманс у него ниже плинтуса. Мы ушли на python.

    Простой пример тут — запрос сколько VM в статусе running (что не тривиально в Azure) — через powershell выполняется 70 минут, python — 5 минут (12.000 виртуалок)
      0
      Хоть я не автор,) но полагаю, что коллега Бертрам хочет просто продемонстрировать возможности автоматизации — без упора на какой-то конкретный способ, просто в сравнении с работой исключительно через консоль. И еще обратить наше внимание на нюансы удаления ВМ в облаке — т.е. на удаление ассоциированных объектов, чтобы не забывали о нём.

      Что до сравнения перфоманса, то спасибо за Ваш пример с python. Задам вопрос коллегам, возможно, кто-то из команд рассматривает его или уже применяет для своего облака.
        +1
        Коллеги. будьте очень аккуратны с PWSH.
        Одно дело красота маркетинговая — другое дело реальность.
        В разрезе маленькой инфры (типа стартап) — все отлично. В разрезе транснационального эжнтерпрайза — PWSH огромная боль.
        Вендор его очень активно пушит, но идут постоянно обновления/декоммит модулей, суппорт вечно не знает. что модуль уже out of.
        Чисто из опыта — у меня все крупные компании, кто использует Azure — используют python SDK по максимум.
        Из плюсов (вне топика) — это еще упрощает жизнь. когда используется более одного cloud vendor (у нас AWS + Azure).
        Мы потеряли огромные деньги

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое