Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem 

Agrāk vai vēlāk jebkurš VMware sistēmas administrators sāk automatizēt ikdienas uzdevumus. Viss sākas ar komandrindu, pēc tam nāk PowerShell vai VMware PowerCLI.

Pieņemsim, ka esat apguvis PowerShell nedaudz tālāk par ISE palaišanu un standarta cmdlet izmantošanu no moduļiem, kas darbojas “kaut kāda veida burvju” dēļ. Kad sākat skaitīt virtuālās mašīnas simtos, jūs atklāsiet, ka skripti, kas palīdz mazā mērogā, lielā mērogā darbojas ievērojami lēnāk. 

Šajā situācijā palīdzēs 2 rīki:

  • PowerShell Runspaces – pieeja, kas ļauj paralēli veikt procesu izpildi atsevišķos pavedienos; 
  • Get-View – pamata PowerCLI funkcija, Get-WMIObject analogs sistēmā Windows. Šī cmdlet nevelk objektus, kas pavada entītijas, bet saņem informāciju vienkārša objekta veidā ar vienkāršiem datu tipiem. Daudzos gadījumos tas iznāk ātrāk.

Tālāk es īsi runāšu par katru rīku un parādīšu lietošanas piemērus. Analizēsim konkrētus skriptus un redzēsim, kad viens darbojas labāk par otru. Aiziet!

Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem

Pirmais posms: Runspace

Tātad Runspace ir paredzēts paralēlai uzdevumu apstrādei ārpus galvenā moduļa. Protams, varat palaist citu procesu, kas patērēs daļu atmiņas, procesora utt. Ja jūsu skripts palaižas pāris minūtēs un patērē gigabaitu atmiņas, visticamāk, jums nebūs vajadzīga Runspace. Bet skriptiem desmitiem tūkstošu objektu tas ir vajadzīgs.

Jūs varat sākt mācīties šeit: 
PowerShell Runspaces lietošanas sākšana: 1. daļa

Ko dod Runspace izmantošana:

  • ātrumu, ierobežojot izpildīto komandu sarakstu,
  • paralēla uzdevumu izpilde,
  • drošība.

Šeit ir piemērs no interneta, kad Runspace palīdz:

“Krātuves strīds ir viens no visgrūtāk izsekojamajiem rādītājiem vSphere. Programmā vCenter jūs nevarat vienkārši doties un redzēt, kura virtuālā mašīna patērē vairāk krātuves resursu. Par laimi, pateicoties PowerShell, jūs varat savākt šos datus dažu minūšu laikā.
Es dalīšos ar skriptu, kas ļaus VMware sistēmas administratoriem ātri meklēt visā vCenter un saņemt VM sarakstu ar datiem par to vidējo patēriņu.  
Skripts izmanto PowerShell izpildvietas, lai ļautu katram ESXi resursdatoram savākt patēriņa informāciju no savām virtuālajām mašīnām atsevišķā Runspace un nekavējoties ziņot par pabeigšanu. Tas ļauj PowerShell nekavējoties aizvērt darbus, nevis iterēt caur saimniekdatoriem un gaidīt, līdz katrs izpildīs savu pieprasījumu.

Avots: Kā parādīt virtuālās mašīnas I/O ESXi informācijas panelī

Tālāk norādītajā gadījumā Runspace vairs nav noderīgs.

“Es mēģinu uzrakstīt skriptu, kas apkopo daudz datu no virtuālās mašīnas un raksta jaunus datus, kad nepieciešams. Problēma ir tā, ka virtuālo mašīnu ir diezgan daudz, un vienai mašīnai tiek pavadītas 5-8 sekundes. 

Avots: Multithreading PowerCLI ar RunspacePool

Šeit jums būs nepieciešams Get-View, pāriesim pie tā. 

Otrais posms: Get-View

Lai saprastu, kāpēc Get-View ir noderīgs, ir vērts atcerēties, kā parasti darbojas cmdlet. 

Cmdlet ir nepieciešamas, lai ērti iegūtu informāciju bez nepieciešamības izpētīt API atsauces grāmatas un no jauna izgudrot nākamo riteni. Kas vecos laikos prasīja simts vai divas koda rindiņas, PowerShell ļauj izdarīt ar vienu komandu. Mēs par šīm ērtībām maksājam ar ātrumu. Pašās cmdlets iekšienē nav nekādas maģijas: tas pats skripts, bet zemākā līmenī, ko raksta prasmīgas meistara rokas no saulainās Indijas.

Tagad, lai salīdzinātu ar Get-View, ņemsim Get-VM cmdlet: tā piekļūst virtuālajai mašīnai un atgriež saliktu objektu, tas ir, pievieno tai citus saistītos objektus: VMHost, Datastore utt.  

Get-View savā vietā neko lieku nepievieno atdotajam objektam. Turklāt tas ļauj mums stingri norādīt, kāda informācija mums ir nepieciešama, kas atvieglos izvades objektu. Windows Server kopumā un jo īpaši Hyper-V cmdlet Get-WMIObject ir tiešs analogs - ideja ir tieši tāda pati.

Get-View ir neērti ikdienas darbībām ar punktveida objektiem. Bet, runājot par tūkstošiem un desmitiem tūkstošu objektu, tam nav cenas.

Vairāk varat lasīt VMware emuārā: Ievads Get-View

Tagad es jums visu parādīšu, izmantojot reālu lietu. 

Skripta rakstīšana VM izlādēšanai

Kādu dienu mans kolēģis man lūdza optimizēt viņa scenāriju. Uzdevums ir parasta rutīna: atrodiet visas virtuālās mašīnas ar dublikātu cloud.uuid (jā, tas ir iespējams, klonējot virtuālo mašīnu vCloud Director). 

Acīmredzamais risinājums, kas nāk prātā, ir:

  1. Iegūstiet visu virtuālo mašīnu sarakstu.
  2. Parsējiet sarakstu kaut kā.

Sākotnējā versija bija šāds vienkāršais skripts:

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
}
# Далее РУКАМИ парсим полученный результат

Viss ir ārkārtīgi vienkārši un skaidri. To var uzrakstīt pāris minūtēs ar kafijas pauzi. Pieskrūvējiet filtrēšanu, un tas ir darīts.

Bet mērīsim laiku:

Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem

Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem

2 minūtes 47 sekundes apstrādājot gandrīz 10 XNUMX virtuālo mašīnu. Bonuss ir filtru trūkums un nepieciešamība manuāli kārtot rezultātus. Acīmredzot skriptam ir nepieciešama optimizācija.

Runspaces ir pirmās, kas nāk palīgā, ja vienlaikus ir jāiegūst resursdatora metrika no vCenter vai jāapstrādā desmitiem tūkstošu objektu. Apskatīsim, ko šī pieeja nesīs.

Ieslēdziet pirmo ātrumu: PowerShell Runspaces

Pirmais, kas nāk prātā šim skriptam, ir izpildīt cilpu nevis secīgi, bet paralēlos pavedienos, savākt visus datus vienā objektā un filtrēt. 

Bet pastāv problēma: PowerCLI neļaus mums atvērt daudzas neatkarīgas sesijas vCenter un radīs smieklīgu kļūdu:

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.

Lai to atrisinātu, vispirms straumē ir jānodod sesijas informācija. Atcerēsimies, ka PowerShell darbojas ar objektiem, kurus var nodot kā parametru funkcijai vai ScriptBlock. Nodosim sesiju šāda objekta formā, apejot $global:DefaultVIServers (Connect-VIServer ar taustiņu -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 $_
           }
       }
   }

Tagad ieviesīsim daudzpavedienu izveidi, izmantojot Runspace Pools.  

Algoritms ir šāds:

  1. Mēs iegūstam visu virtuālo mašīnu sarakstu.
  2. Paralēlās plūsmās iegūstam cloud.uuid.
  3. Mēs apkopojam datus no straumēm vienā objektā.
  4. Mēs filtrējam objektu, grupējot to pēc CloudUUID lauka vērtības: tie, kuros unikālo vērtību skaits ir lielāks par 1, ir mūsu meklētās virtuālās mašīnas.

Rezultātā mēs iegūstam skriptu:


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
}

Šī skripta skaistums ir tāds, ka to var izmantot citos līdzīgos gadījumos, vienkārši nomainot ScriptBlock un parametrus, kas tiks nodoti straumei. Izmanto to!

Mēs izmērām laiku:

Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem

55 sekundes. Tas ir labāk, bet tas joprojām var būt ātrāks. 

Pārejam uz otro ātrumu: GetView

Noskaidrosim, kas par vainu.
Pirmkārt un galvenokārt, Get-VM cmdlet izpilde prasa ilgu laiku.
Otrkārt, Get-AdvancedOptions cmdlet pabeigšana prasa vēl ilgāku laiku.
Vispirms tiksim galā ar otro. 

Get-AdvancedOptions ir ērts atsevišķiem VM objektiem, taču ļoti neveikls, strādājot ar daudziem objektiem. To pašu informāciju varam iegūt no paša virtuālās mašīnas objekta (Get-VM). Tas vienkārši ir labi aprakts ExtensionData objektā. Apbruņojušies ar filtrēšanu, mēs paātrinam nepieciešamo datu iegūšanas procesu.

Ar nelielu rokas kustību tas ir:


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

Pārvēršas par šo:


$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}}

Izvade ir tāda pati kā Get-AdvancedOptions, taču tā darbojas daudzas reizes ātrāk. 

Tagad uz Get-VM. Tas nav ātrs, jo tas attiecas uz sarežģītiem objektiem. Rodas loģisks jautājums: kāpēc mums šajā gadījumā ir vajadzīga papildu informācija un zvērīgs PSObject, ja mums ir nepieciešams tikai VM nosaukums, tā stāvoklis un viltīga atribūta vērtība?  

Turklāt no skripta ir noņemts šķērslis Get-AdvancedOptions veidā. Runspace Pools izmantošana tagad šķiet pārspīlēta, jo, nododot sesiju, vairs nav nepieciešams paralēli veikt lēnu uzdevumu pāri squat pavedieniem. Instruments ir labs, bet ne šim gadījumam. 

Apskatīsim ExtensionData izvadi: tas ir nekas vairāk kā Get-View objekts. 

Piesauksim seno PowerShell meistaru tehniku: viena rinda, izmantojot filtrus, šķirošanu un grupēšanu. Visas iepriekšējās šausmas ir eleganti saliktas vienā rindā un izpildītas vienā seansā:


$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

Mēs izmērām laiku:

Kā izveidot raķešu pastiprinātāju PowerCLI skriptiem

9 sekundes gandrīz 10 XNUMX objektu ar filtrēšanu pēc vēlamā stāvokļa. Lieliski!

Tā vietā, lai noslēgtu

Pieņemams rezultāts ir tieši atkarīgs no instrumenta izvēles. Bieži vien ir grūti precīzi pateikt, kas tieši būtu jāizvēlas, lai to sasniegtu. Katra no uzskaitītajām metodēm skriptu paātrināšanai ir laba tās pielietojamības robežās. Es ceru, ka šis raksts jums palīdzēs grūtajā uzdevumā – izprast procesu automatizācijas un optimizācijas pamatus jūsu infrastruktūrā.

PS: Autore pateicas visiem kopienas locekļiem par palīdzību un atbalstu raksta sagatavošanā. Pat tie, kuriem ir ķepas. Un pat tie, kuriem nav kāju, piemēram, boa konstriktors.

Avots: www.habr.com

Pievieno komentāru