Повышение доступности кластеров – эвакуация виртуальных машин при перезагрузке


Кластеризация виртуальных машин повышает их доступность. Технология Live Migration позволяет администратору планово перенести виртуальную машину с одного узла на другой без потери соединений к данной машине. SCVMM 2008 R2 позволяет администратору включить для узла режим обслуживания, что по очереди перенесёт все виртуальные машины на другие узлы, динамически распределив их в зависимости от текущей нагрузки на узлах кластера.

Это звучит замечательно, когда вы планируете сами перенести виртуальную машину или перезагрузить сервер виртуализации. Если вы, не предприняв особых действий, захотите перезагрузить узел кластера, то все виртуальные машины на этом узле сохранят своё состояние на жесткий диск и переедут на другие узлы при остановке службы кластера. По сути, можно сказать, что будет использоваться Quick Migration для данных машин с временем её недоступности от 30 до 90 секунд. Это уже не всегда приемлемо для продуктивных систем, так что администраторы пытаются по возможности не перезагружать узлы виртуализации. Вам интересно, как повысить доступность ваших виртуальных машин, настроив операционную систему на эвакуацию виртуальных машин при перезагрузке и выключении сервера виртуализации? Рассмотрим небольшой пример.

Небольшой скрипт PowerShell, который мы добавим в локальную или доменную политику на сервере виртуализации выполнит эвакуацию всех виртуальных машин при выключении или перезагрузке:

Сценарий PowerShell Evac-VMs.ps1

ImportSystemModules

$Computer = Get-Content env:ComputerName

Suspend-ClusterNode $Computer

$AvailNodes = (get-clusternode | Where-Object { $_.State -eq "Up" -and $_.Name -ne "$Computer" })

$i = 0

$VMGroups = Get-ClusterNode $Computer| Get-ClusterGroup | ?{ $_ | Get-ClusterResource | ?{ $_.ResourceType -like "Virtual Machine" } }

foreach ( $VMGroup in $VMGroups ) {

Move-ClusterVirtualMachineRole "$VMGroup" -Node $AvailNodes[$i].Name

$i = $i + 1

if ($i -eq $AvailNodes.Count) { $i = 0 }

}

Resume-ClusterNode $Computer

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

Далее мы составляем список всех доступных узлов нашего кластера. Получаем список всех групп виртуальных машин, запущенных на нашем узле и начинаем поочередно переносить их на другие узлы кластера используя Live Migration.

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

Имея данный скрипт, например в C:\Scripts\Evac-VMs.PS1 на каждом узле кластера, нам требуется сделать еще один шаг, чтобы скрипт мог выполняться. Есть два варианта:

  1. Подписать данный скрипт. Понадобится иметь Code Signing сертификат, возможно, самостоятельно сгенерированный на этом узле. Далее выполнить подписание: $cert = @(gci cert:\currentuser\CodeSigningCert)[0]; Set-AuthenticodeSignature Evac-VMs.ps1 $cert)
  2. Разрешить неограниченное исполнение неподписанных скриптов: Set-ExecutionPolicy -ExecutionPolicy Unrestricted

На самом деле PowerShell скрипты, исполняемые групповыми политиками не требуют обязательного подписания, поскольку всегда запускаются в неограниченной политике исполнения. При этом я всё-таки рекомендую вам подписывать скрипты, чтобы вы могли их вручную протестировать и быть уверенными, что они не были изменены после подписания.

В итоге нам остается добавить данный скрипт в локальную или доменную политику, определяющую скрипты, исполняющиеся при выключении/перезагрузке. Для этого в редакторе политик откроем раздел Computer Configuration\Windows Settings\Scripts:


В настройке Shutdown выберем закладку PowerShell Scripts (не перепутайте) и укажем, что они запускаются первыми:


Укажем путь до нашего скрипта:


К заметке прилагается неподписанный пример скрипта. Если у вас есть комментарии или идеи по оптимизации, буду рад их услышать.

Comments (6)

  1. Alex A says:

    Попробуйте, исправить 7ую строчку на:

    $AvailNodes = @(get-clusternode | Where-Object { $_.State -eq "Up" -and $_.Name -ne "$Computer" })

    И можно еще 10 на:

    $VMGroups = @(Get-ClusterNode $Computer| Get-ClusterGroup | ?{ $_ | Get-ClusterResource | ?{ $_.ResourceType -like "Virtual Machine" } })

    Я не ожидал что включенных виртуалок будет 1 штука, или в кластере будет всего один узел..

    Дело в том что если в результате команды мы получаем несколько объектов, то PowerShell возвращает их в виде массива, а если объект один, то PowerShell возвращает его как есть, без массивов.

    Кострукция @() позволяет превратить содержмое скобок в массив, даже если это будет массив из одного или нуля элементов. Если внутри и так массив – он останется неизменным.

    Расскажите о результате!

  2. Alex A says:

    Это нормально.

    Вы либо загружаете (импортируете) модули при каждом запуске "пустого" PowerShell, либо запускаете "тяжелый" со всеми модулями.

    Можно прописать модуль failoverclusters к автозапуску в "пустом" режиме, тогда ничего не придется делать.

  3. Anonymous says:

    Вопрос и по теме и не очень..

    В blogs.technet.com/…/cluster-shared-volumes.aspx Вы писали, что для работы с командлетом Get-Cluster надо импортировать модуль failoverclusters или запускать «Windows PowerShell Modules» из «Administrative Tools». Делаю и так и так, получается..

    Но.. если сомандлет Get-Cluster использую в той-же сессии, что и ImportSystemModules! Как только я закрываю эту сессию PowerShell то все- опять ничего про кластер нет!

    Это нормально? Или я сильно туплю?

    Спасибо!

  4. Sergey says:

    Alex, здравствйте, у меня есть вопрос. Непонятна сама постановка проблемы: "не предприняв особых действий, захотите перезагрузить узел кластера". Какие вообще варианты перезагрузки узла возможны? Я придумал вот такие:

    1. Предварительная миграция ВМ с узла на другие узлы, остановка cluster service, перезагрузка средствами ОС.

    2. Остановка cluster service, затем перезагрузка средствами ОС.

    3. Перезагрузка средствами ОС без какой-либо подготовки.

    4. Перезагрузка по питанию (ресет).

    В каком из этих случаев возникнут проблемы? Имеется в виду, виртуальная машина будет перезапущена на другом узле, что приведёт к потере соединения? В случаях 2,3,4. То есть в случае любого отключения узла без предварительной миграции машин.

    Теперь вопрос: правильно ли я понял, что вы предлагаете заплатку именно для случая 3?

  5. Roman says:

    Возникает ошибка

    Unable to index into an object of type Microsoft.FailoverClusters.PowerShell.ClusterNode.

    At C:ScriptsEvac-VMs.ps1:12 char:15

    +   $AvailNodes[ <<<< $i].Name

       + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException

  6. Roman says:

    Да, так лучше 🙂

    работает.

    Но виртуалок на ноде было не 1, а 30.

Skip to main content