PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек 

Эртеби-кечпи, каалаган VMware системалык администратору күнүмдүк тапшырмаларды автоматташтыруу үчүн келет. Мунун баары буйрук сабынан башталат, андан кийин PowerShell же VMware PowerCLI келет.

Сиз PowerShellди ISEди ишке киргизүүдөн жана "кандайдыр бир сыйкырдын" аркасында иштеген модулдардан стандарттуу командлеттерди колдонуудан бир аз көбүрөөк өздөштүрүп алдыңыз дейли. Сиз жүздөгөн виртуалдык машиналарды санай баштаганыңызда, кичине масштабда жардам берген скрипттер чоң масштабда байкаларлык жайыраак иштей турганын көрөсүз. 

Бул учурда, эки курал жардам берет:

  • PowerShell Runspaces – өзүнчө жиптерде процесстердин аткарылышын параллелдештирүүгө мүмкүндүк берүүчү ыкма; 
  • Get-View – негизги PowerCLI функциясы, Windows ичиндеги Get-WMIObject аналогу. Бул командлет объекттерди коштогон объекттерди тартпайт, бирок жөнөкөй маалымат түрлөрү менен жөнөкөй объект түрүндө маалыматты алат. Көп учурларда ал тезирээк чыгат.

Андан кийин, мен ар бир курал жөнүндө кыскача айтып, колдонуу мисалдарын көрсөтөм. Келгиле, конкреттүү скрипттерди талдап көрөлү жана качан бири экинчисине караганда жакшыраак иштей турганын көрөлү. Go!

PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек

Биринчи этап: Runspace

Ошентип, Runspace негизги модулдан тышкары милдеттерди параллелдүү иштетүү үчүн иштелип чыккан. Албетте, сиз эстутумду, процессорду ж.б. жей турган башка процессти ишке киргизсеңиз болот. Эгер скриптиңиз бир-эки мүнөттүн ичинде иштеп, бир гигабайт эстутумду керектесе, сизге Runspace керек болбой калышы мүмкүн. Бирок он миңдеген объектилердин сценарийлери үчүн ал керек.

Сиз бул жерден үйрөнө баштасаңыз болот: 
PowerShell Rnspaces колдонуунун башталышы: 1-бөлүк

Runspace колдонуу эмнени берет:

  • аткарылган буйруктардын тизмесин чектөө менен ылдамдык,
  • милдеттерди параллелдүү аткаруу,
  • коопсуздук.

Бул жерде Runspace жардам берген Интернеттен мисал:

"Сактоо талашы vSphereде байкоо жүргүзүү үчүн эң кыйын көрсөткүчтөрдүн бири. vCenter ичинде, сиз жөн эле барып, кайсы VM көбүрөөк сактоо ресурстарын керектеп жатканын көрө албайсыз. Бактыга жараша, сиз PowerShell жардамы менен бул маалыматты бир нече мүнөттүн ичинде чогулта аласыз.
Мен VMware тутумунун администраторлоруна vCenter боюнча тез издөөгө жана алардын орточо керектөө маалыматтары менен VMлердин тизмесин алууга мүмкүндүк берген скрипт менен бөлүшөм.  
Скрипт PowerShell иштөө мейкиндиктерин колдонот, бул ар бир ESXi хостуна өзүнчө Runspace ичинде өзүнүн VM'деринен керектөө маалыматын чогултууга жана дароо аяктагандыгы жөнүндө отчет берүүгө мүмкүндүк берет. Бул PowerShellге хосттор аркылуу итерациялоонун жана алардын ар бири өзүнүн суроо-талабын аяктоосун күтүүнүн ордуна, жумуштарды дароо жабууга мүмкүндүк берет."

Source: ESXi тактасында Virtual Machine I/Oну кантип көрсөтүү керек

Төмөнкү учурда, Runspace мындан ары пайдалуу эмес:

«Мен VMден көп маалыматтарды чогултуучу жана керек болгондо жаңы маалыматтарды жаза турган сценарий жазууга аракет кылып жатам. Көйгөй, VM-лер абдан көп жана бир машинага 5-8 секунд сарпталат». 

Source: RunspacePool менен көп агымдуу PowerCLI

Бул жерде сизге Get-View керек болот, ага өтөбүз. 

Экинчи этап: Get-View

Get-View эмне үчүн пайдалуу экенин түшүнүү үчүн, жалпысынан cmdlets кантип иштээрин эстен чыгарбоо керек. 

Cmdlet'тер API маалымдама китептерин изилдөөнүн жана кийинки дөңгөлөктү кайра ойлоп табуунун зарылдыгы жок маалыматты ыңгайлуу алуу үчүн керек. Мурунку күндөрдө жүз же эки сап кодду талап кылган PowerShell сизге бир буйрук менен аткарууга мүмкүндүк берет. Бул ыңгайлуулук үчүн биз ылдамдык менен төлөйбүз. Комдлеттердин ичинде эч кандай сыйкыр жок: ошол эле сценарий, бирок андан төмөн деңгээлде, күнөстүү Индиядан келген чебердин чебер колдору менен жазылган.

Эми Get-View менен салыштыруу үчүн Get-VM командлетин алалы: ал виртуалдык машинага кирип, курама объектти кайтарат, башкача айтканда, ага башка тиешелүү объекттерди тиркейт: VMHost, Datastore ж.б.  

Анын ордуна Get-View кайтарылган объектке керексиз эч нерсе кошпойт. Мындан тышкары, ал бизге кандай маалымат керек экенин так көрсөтүүгө мүмкүндүк берет, бул чыгаруу объектисин жеңилдетет. Жалпысынан Windows серверинде жана өзгөчө Hyper-Vде Get-WMIObject командлети түз аналог болуп саналат - идея дал ушундай.

Get-View чекиттик объектилерде күнүмдүк операциялар үчүн ыңгайсыз. Ал эми миңдеген жана он миңдеген объекттерге келгенде анын баасы жок.

VMware блогунан көбүрөөк окуй аласыз: Get-View программасына киришүү

Эми мен сизге чыныгы иштин жардамы менен баарын көрсөтөм. 

VM жүктөө үчүн сценарий жазуу

Бир күнү менин кесиптешим анын сценарийин оптималдаштырууну суранды. Тапшырма жалпы көнүмүш болуп саналат: кайталанма cloud.uuid параметри бар бардык VMлерди табыңыз (ооба, бул vCloud Directorде VM клондоодо мүмкүн). 

акылга келген ачык чечим болуп саналат:

  1. Бардык VMлердин тизмесин алыңыз.
  2. Тизмени кандайдыр бир жол менен талдоо.

баштапкы версия бул жөнөкөй скрипт болгон:

function Get-CloudUUID1 {
   # Получаем список всех ВМ
   $vms = Get-VM
   $report = @()

   # Обрабатываем каждый объект, получая из него только 2 свойства: Имя ВМ и Cloud UUID.
   # Заносим данные в новый PS-объект с полями VM и UUID
   foreach ($vm in $vms)
   {
       $table = "" | select VM,UUID

       $table.VM = $vm.name
       $table.UUID = ($vm | Get-AdvancedSetting -Name cloud.uuid).Value
          
       $report += $table
   }
# Возвращаем все объекты
   $report
}
# Далее РУКАМИ парсим полученный результат

Баары абдан жөнөкөй жана түшүнүктүү. Кофе-брейк менен бир-эки мүнөттө жазса болот. Фильтрацияны бурап, бүттү.

Бирок убакытты өлчөп көрөлү:

PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек

PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек

2 мүнөт 47 секунд дээрлик 10k VM иштетүүдө. Бонус - бул чыпкалардын жоктугу жана натыйжаларды кол менен сорттоо зарылчылыгы. Албетте, скрипт оптималдаштырууну талап кылат.

Runspaces бир эле убакта vCenter'ден хосттун метрикасын алуу керек болгондо же он миңдеген объектилерди иштетүү керек болгондо биринчилерден болуп жардамга келет. Келгиле, бул ыкма эмне алып келерин карап көрөлү.

Биринчи ылдамдыкты күйгүзүңүз: PowerShell Runspaces

Бул скрипт үчүн биринчи ойго келе турган нерсе - циклди ырааттуу эмес, параллелдүү жиптерде аткаруу, бардык маалыматтарды бир объектке чогултуу жана аны чыпкалоо. 

Бирок бир көйгөй бар: PowerCLI бизге vCenterге көптөгөн көз карандысыз сессияларды ачууга мүмкүндүк бербейт жана күлкүлүү ката кетирет:

You have modified the global:DefaultVIServer and global:DefaultVIServers system variables. This is not allowed. Please reset them to $null and reconnect to the vSphere server.

Муну чечүү үчүн алгач сеанс маалыматын агымдын ичине өткөрүп беришиңиз керек. PowerShell функцияга же ScriptBlock'ка параметр катары берилүүчү объекттер менен иштей турганын эстейли. $global:DefaultVIServers (Connect-VIServer -NotDefault ачкычы менен) айланып өтүп, ушундай объект түрүндө сессияны өткөрөлү:

$ConnectionString = @()
foreach ($vCenter in $vCenters)
   {
       try {
           $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -AllLinked -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
       }
       catch {
           if ($er.Message -like "*not part of a linked mode*")
           {
               try {
                   $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
               }
               catch {
                   throw $_
               }
              
           }
           else {
               throw $_
           }
       }
   }

Эми Runspace Pools аркылуу көп агымды ишке ашыралы.  

Алгоритм төмөнкүчө:

  1. Биз бардык VMлердин тизмесин алабыз.
  2. Параллелдүү агымдарда биз cloud.uuid алабыз.
  3. Биз агымдардан маалыматтарды бир объектке чогултабыз.
  4. Биз объектти CloudUUID талаасынын мааниси боюнча топтоо аркылуу чыпкалайбыз: уникалдуу маанилердин саны 1ден көп болгондор биз издеп жаткан VMлер.

Натыйжада, биз сценарийди алабыз:


function Get-VMCloudUUID {
   param (
       [string[]]
       [ValidateNotNullOrEmpty()]
       $vCenters = @(),
       [int]$MaxThreads,
       [System.Management.Automation.PSCredential]
       [System.Management.Automation.Credential()]
       $Credential
   )

   $ConnectionString = @()

   # Создаем объект с сессионным ключом
   foreach ($vCenter in $vCenters)
   {
       try {
           $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -AllLinked -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
       }
       catch {
           if ($er.Message -like "*not part of a linked mode*")
           {
               try {
                   $ConnectionString += Connect-VIServer -Server $vCenter -Credential $Credential -NotDefault -Force -ErrorAction stop -WarningAction SilentlyContinue -ErrorVariable er
               }
               catch {
                   throw $_
               }
              
           }
           else {
               throw $_
           }
       }
   }

   # Получаем список всех ВМ
   $Global:AllVMs = Get-VM -Server $ConnectionString

   # Поехали!
   $ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
   $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
   $RunspacePool.ApartmentState = "MTA"
   $RunspacePool.Open()
   $Jobs = @()

# ScriptBlock с магией!)))
# Именно он будет выполняться в потоке
   $scriptblock = {
       Param (
       $ConnectionString,
       $VM
       )

       $Data = $VM | Get-AdvancedSetting -Name Cloud.uuid -Server $ConnectionString | Select-Object @{N="VMName";E={$_.Entity.Name}},@{N="CloudUUID";E={$_.Value}},@{N="PowerState";E={$_.Entity.PowerState}}

       return $Data
   }
# Генерируем потоки

   foreach($VM in $AllVMs)
   {
       $PowershellThread = [PowerShell]::Create()
# Добавляем скрипт
       $null = $PowershellThread.AddScript($scriptblock)
# И объекты, которые передадим в качестве параметров скрипту
       $null = $PowershellThread.AddArgument($ConnectionString)
       $null = $PowershellThread.AddArgument($VM)
       $PowershellThread.RunspacePool = $RunspacePool
       $Handle = $PowershellThread.BeginInvoke()
       $Job = "" | Select-Object Handle, Thread, object
       $Job.Handle = $Handle
       $Job.Thread = $PowershellThread
       $Job.Object = $VM.ToString()
       $Jobs += $Job
   }

# Ставим градусник, чтобы наглядно отслеживать выполнение заданий
# И здесь же прибиваем отработавшие задания
   While (@($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0)
   {
       $Remaining = "$($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).object)"

       If ($Remaining.Length -gt 60) {
           $Remaining = $Remaining.Substring(0,60) + "..."
       }

       Write-Progress -Activity "Waiting for Jobs - $($MaxThreads - $($RunspacePool.GetAvailableRunspaces())) of $MaxThreads threads running" -PercentComplete (($Jobs.count - $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count)) / $Jobs.Count * 100) -Status "$(@($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False})).count) remaining - $remaining"

       ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){
           $Job.Thread.EndInvoke($Job.Handle)     
           $Job.Thread.Dispose()
           $Job.Thread = $Null
           $Job.Handle = $Null
       }
   }

   $RunspacePool.Close() | Out-Null
   $RunspacePool.Dispose() | Out-Null
}


function Get-CloudUUID2
{
   [CmdletBinding()]
   param(
   [string[]]
   [ValidateNotNullOrEmpty()]
   $vCenters = @(),
   [int]$MaxThreads = 50,
   [System.Management.Automation.PSCredential]
   [System.Management.Automation.Credential()]
   $Credential)

   if(!$Credential)
   {
       $Credential = Get-Credential -Message "Please enter vCenter credentials."
   }

   # Вызов функции Get-VMCloudUUID, где мы распараллеливаем операцию
   $AllCloudVMs = Get-VMCloudUUID -vCenters $vCenters -MaxThreads $MaxThreads -Credential $Credential
   $Result = $AllCloudVMs | Sort-Object Value | Group-Object -Property CloudUUID | Where-Object -FilterScript {$_.Count -gt 1} | Select-Object -ExpandProperty Group
   $Result
}

Бул скрипттин кооздугу, аны ScriptBlock жана агымга өтө турган параметрлерди алмаштыруу менен башка ушул сыяктуу учурларда колдонсо болот. Аны пайдалануу!

Биз убакытты өлчөйбүз:

PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек

55 секунд. Бул жакшыраак, бирок дагы эле тезирээк болушу мүмкүн. 

Экинчи ылдамдыкка өтөлү: GetView

Келгиле, эмне болуп жатканын билели.
Биринчи кезекте, Get-VM командлетинин аткарылышы көп убакытты талап кылат.
Экинчиден, Get-AdvancedOptions командлетин бүтүрүү үчүн дагы көп убакыт талап кылынат.
Адегенде экинчисин чечели. 

Get-AdvancedOptions жеке VM объектилери үчүн ыңгайлуу, бирок көптөгөн объекттер менен иштөөдө өтө олдоксон. Биз ошол эле маалыматты виртуалдык машина объектинин өзүнөн ала алабыз (Get-VM). Бул жөн гана ExtensionData объектисинде жакшы көмүлгөн. Чыпкалоо менен куралданган биз керектүү маалыматтарды алуу процессин тездетип жатабыз.

Колдун бир аз кыймылы менен бул:


VM | Get-AdvancedSetting -Name Cloud.uuid -Server $ConnectionString | Select-Object @{N="VMName";E={$_.Entity.Name}},@{N="CloudUUID";E={$_.Value}},@{N="PowerState";E={$_.Entity.PowerState}}

Буга айланат:


$VM | Where-Object {($_.ExtensionData.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value -ne $null} | Select-Object @{N="VMName";E={$_.Name}},@{N="CloudUUID";E={($_.ExtensionData.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value}},@{N="PowerState";E={$_.summary.runtime.powerstate}}

Чыгуу Get-AdvancedOptions менен бирдей, бирок ал бир нече эсе тезирээк иштейт. 

Азыр Get-VM. Ал татаал объектилер менен алектенгендиктен тез эмес. Логикалык суроо туулат: эмне үчүн бизге VM аты, анын абалы жана татаал атрибуттун мааниси керек болгондо, бул учурда бизге кошумча маалымат жана коркунучтуу PSObject керек?  

Мындан тышкары, Get-AdvancedOptions түрүндөгү тоскоолдук сценарийден алынып салынды. Runspace Pools колдонуу азыр ашыкча эле сезилет, анткени сеансты өткөрүп жатканда скват жиптери боюнча жай тапшырманы параллелдештирүүнүн кереги жок. курал жакшы, бирок бул учурда эмес. 

ExtensionData натыйжасын карап көрөлү: бул Get-View объектинен башка эч нерсе эмес. 

Келгиле, PowerShell чеберлеринин байыркы техникасына кайрылалы: чыпкаларды колдонуу, сорттоо жана топтоо. Мурунку үрөй учурарлык көрүнүштөрдүн баары бир сапка бириктирилип, бир сессияда аткарылат:


$AllVMs = Get-View -viewtype VirtualMachine -Property Name,Config.ExtraConfig,summary.runtime.powerstate | Where-Object {($_.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value -ne $null} | Select-Object @{N="VMName";E={$_.Name}},@{N="CloudUUID";E={($_.Config.ExtraConfig | Where-Object {$_.key -eq "cloud.uuid"}).Value}},@{N="PowerState";E={$_.summary.runtime.powerstate}} | Sort-Object CloudUUID | Group-Object -Property CloudUUID | Where-Object -FilterScript {$_.Count -gt 1} | Select-Object -ExpandProperty Group

Биз убакытты өлчөйбүз:

PowerCLI скрипттери үчүн ракета күчөткүчтү кантип куруу керек

9 секунд каалаган шарты боюнча чыпкалоо менен дээрлик 10k объекттер үчүн. Абдан жакшы!

Ордуна корутундусу

Алгылыктуу натыйжа түздөн-түз куралды тандоодон көз каранды. Ага жетүү үчүн эмнени так тандоо керек экенин так айтуу көп учурда кыйын. Скрипттерди тездетүү үчүн саналып өткөн ыкмалардын ар бири өзүнүн колдонуу мүмкүнчүлүгүнүн чегинде жакшы. Бул макала сизге инфраструктураңыздагы процесстерди автоматташтыруунун жана оптималдаштыруунун негиздерин түшүнүү боюнча татаал тапшырмада жардам берет деп ишенем.

PS: Автор макаланы даярдоодо көрсөткөн жардамы жана колдоосу үчүн коомчулуктун бардык мүчөлөрүнө ыраазычылык билдирет. Жада калса буттары барлар да. Ал тургай, буту жоктор, боа констриктору сыяктуу.

Source: www.habr.com

Комментарий кошуу