ADG Оставить заявку
Блог Автоматизация 4 мин чтения

PowerShell 3.0 и Workflows: параллельное развёртывание патчей на 20 серверах без велосипедов

PowerShell 3.0 в Windows 8 и Server 2012 приносит Workflows и ForEach -Parallel. Пишем первый workflow для одновременного патчинга группы серверов и смотрим, что изменилось.

Контекст момента

PowerShell 3.0 включён в Windows 8 и Windows Server 2012 RC: Workflows на базе WF4, Scheduled Jobs, улучшенный ISE с IntelliSense и автодополнением параметров

PowerShell 3.0 не нужно скачивать отдельно - он входит в Windows 8 и Windows Server 2012 RC, который мы уже тестируем на стендах. Новая версия бросается в глаза сразу: ISE с IntelliSense, автодополнение параметров прямо в консоли, нормальная справка через Update-Help. Но главное, что нас зацепило - Workflows.

Что такое Workflow и чем он отличается от обычного скрипта

Workflow в PowerShell 3.0 - это блок workflow { ... } вместо function { ... }, под капотом которого работает Windows Workflow Foundation 4. Это не просто синтаксический сахар. Из практически важного:

  • Checkpoint'ы и возобновление. Workflow можно приостановить, сервер перезагрузить и продолжить с точки Checkpoint-Workflow. Для патчинга с рестартами это не абстрактная фича.
  • Параллельное выполнение. ForEach -Parallel и блок Parallel { ... } позволяют гонять операции одновременно на нескольких целях без возни с runspace и job-ами вручную.
  • Встроенная поддержка PSRemoting. Параметр -PSComputerName прямо в сигнатуре workflow - и он сам разворачивает выполнение по списку хостов.

Scheduled Jobs - тоже удобное добавление: задания через Register-ScheduledJob интегрированы с планировщиком Windows и возвращают нормальные объекты с историей запусков. Мы раньше лепили это через сочетание schtasks.exe и скриптов-обёрток - теперь проще.

Задача: патчинг группы серверов

У одного из клиентов - парк из двух десятков Windows-серверов разного возраста. WSUS есть, одобрение обновлений налажено, но сам процесс установки патчей до сих пор шёл последовательно: скрипт на PowerShell 2.0 обходил сервер за сервером, дожидался завершения установки, перезагрузки, проверки - и шёл к следующему. Окно обслуживания на 20 машин занимало около двух часов, притом что большую часть времени скрипт просто ждал.

Первая же мысль при взгляде на ForEach -Parallel: а что если запустить всё одновременно?

Workflow для параллельного патчинга

workflow Install-PatchesParallel {
    param(
        [string[]]$ComputerList,
        [int]$ThrottleLimit = 5
    )

    ForEach -Parallel -ThrottleLimit $ThrottleLimit ($Computer in $ComputerList) {
        sequence {
            InlineScript {
                $session = New-Object -ComObject Microsoft.Update.Session
                $searcher = $session.CreateUpdateSearcher()
                $result = $searcher.Search("IsInstalled=0 and Type='Software'")

                if ($result.Updates.Count -eq 0) {
                    Write-Output "[$using:Computer] Нет ожидающих обновлений"
                    return
                }

                $downloader = $session.CreateUpdateDownloader()
                $downloader.Updates = $result.Updates
                $downloader.Download()

                $installer = $session.CreateUpdateInstaller()
                $installer.Updates = $result.Updates
                $installResult = $installer.Install()

                Write-Output "[$using:Computer] Установлено: $($result.Updates.Count), код: $($installResult.ResultCode)"
            } -PSComputerName $Computer -PSCredential $using:Credential

            Checkpoint-Workflow
        }
    }
}

Несколько замечаний по тому, что получилось:

$using:Variable. В InlineScript переменные из внешнего scope передаются именно так - это специфика Workflows, к ней надо привыкнуть. Первые двадцать минут мы удивлялись, почему $Computer внутри InlineScript всегда пустой.

ThrottleLimit. Без ограничения параллельность упирается в возможности сети и удалённых хостов. 5 одновременных сессий на клиентском стенде показали себя адекватно, на 20 серверах пиков не создавали. Значение подбирается под конкретную инфраструктуру.

Checkpoint-Workflow после каждого хоста. Если что-то пошло не так на середине - workflow можно возобновить, не начиная всё заново. На практике пока не пригодилось, но это как ремень безопасности.

sequence внутри ForEach -Parallel. Шаги для каждого конкретного сервера должны идти последовательно - сначала скачать, потом установить. Без блока sequence Workflow может переставить операции, и это не баг, а намеренное поведение.

Что получилось по времени

Запустили на тестовом стенде из 12 виртуалок (все без обновлений за последние два месяца). С последовательным скриптом - около 80 минут. С ForEach -Parallel при ThrottleLimit = 5 - порядка 22 минут. Разница ощутимая, особенно с учётом того, что кода написали примерно столько же, просто в другом синтаксисе.

На реальных 20 серверах результат будет зависеть от объёма патчей и ширины канала до хостов. Но логика простая: если серверы патчатся примерно одинаково долго, параллельность даёт выигрыш пропорционально степени параллелизма - в разумных пределах ThrottleLimit.

ISE с IntelliSense

Отдельно стоит упомянуть новый ISE. Автодополнение параметров командлетов, подсказки по типам, подсветка переменных - это не революция, но работать приятнее. Раньше мы держали под рукой справочник по параметрам; теперь ISE подсказывает прямо во время набора. Workflow-синтаксис тоже подсвечивается корректно.

Что дальше

Workflow с параметром -PSComputerName на уровне самого workflow - это ещё один вариант, который мы не тестировали: передаёшь весь список сразу, и PowerShell сам занимается параллельным выполнением. Разберём в следующий раз.

Для сопровождения серверной инфраструктуры PowerShell 3.0 - ощутимый шаг вперёд. Не нужно изобретать параллельный патчинг через Start-Job и Wait-Job с колхозной синхронизацией - теперь есть штатный инструмент. Пока Workflows ведут себя предсказуемо на тестовом стенде; насколько они устойчивы в продакшне на Server 2012 GA - увидим после релиза.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.