Rakettivahvistimen rakentaminen PowerCLI-skripteille 

Ennemmin tai myöhemmin kuka tahansa VMware-järjestelmänvalvoja tulee automatisoimaan rutiinitehtävät. Kaikki alkaa komentoriviltä, ​​jonka jälkeen tulee PowerShell tai VMware PowerCLI.

Oletetaan, että olet oppinut PowerShellin hieman pidemmälle kuin käynnistämällä ISE:n ja käyttämällä tavallisia cmdlet-komentoja moduuleista, jotka toimivat "jonkin taikuuden vuoksi". Kun alat laskea virtuaalikoneita satoihin, huomaat, että pienessä mittakaavassa hyödylliset skriptit toimivat huomattavasti hitaammin suuressa mittakaavassa. 

Tässä tilanteessa 2 työkalua auttavat:

  • PowerShell Runspaces – lähestymistapa, jonka avulla voit rinnastaa prosessien suorittamisen erillisissä säikeissä; 
  • Hanki-View – PowerCLI-perustoiminto, analoginen Get-WMIObjectille Windowsissa. Tämä cmdlet ei vedä entiteettien mukana olevia objekteja, vaan vastaanottaa tietoa yksinkertaisen objektin muodossa yksinkertaisilla tietotyypeillä. Monissa tapauksissa se tulee ulos nopeammin.

Seuraavaksi puhun lyhyesti jokaisesta työkalusta ja näytän käyttöesimerkkejä. Analysoidaan tiettyjä skriptejä ja katsotaan, milloin yksi toimii paremmin kuin toinen. Mennä!

Rakettivahvistimen rakentaminen PowerCLI-skripteille

Ensimmäinen vaihe: Runspace

Joten Runspace on suunniteltu tehtävien rinnakkaiskäsittelyyn päämoduulin ulkopuolella. Voit tietysti käynnistää toisen prosessin, joka kuluttaa muistia, prosessoria jne. Jos komentosarjasi suoritetaan muutamassa minuutissa ja kuluttaa gigatavun muistia, et todennäköisesti tarvitse Runspacea. Mutta sitä tarvitaan kymmenien tuhansien objektien skripteille.

Voit aloittaa oppimisen tästä: 
PowerShell-ajotilojen käytön aloittaminen: Osa 1

Mitä Runspacen käyttö antaa:

  • nopeutta rajoittamalla suoritettujen komentojen luetteloa,
  • tehtävien rinnakkainen suorittaminen,
  • turvallisuus.

Tässä on esimerkki Internetistä, kun Runspace auttaa:

"Tallennuskiista on yksi vSpheren vaikeimmin seurattavista mittareista. vCenterissä et voi vain mennä katsomaan, mikä VM kuluttaa enemmän tallennusresursseja. Onneksi voit kerätä nämä tiedot minuuteissa PowerShellin ansiosta.
Jaan skriptin, jonka avulla VMware-järjestelmänvalvojat voivat etsiä nopeasti kaikkialta vCenteristä ja saada luettelon virtuaalikoneista, jotka sisältävät tiedot niiden keskimääräisestä kulutuksesta.  
Komentosarja käyttää PowerShell-ajotiloja, jotta kukin ESXi-isäntä voi kerätä kulutustietoja omista virtuaalikoneistaan ​​erillisessä ajotilassa ja raportoida välittömästi valmistumisesta. Näin PowerShell voi sulkea työt välittömästi sen sijaan, että se iteroisi isäntien läpi ja odottaisi jokaisen suorittavan pyyntönsä."

Lähde: Virtuaalikoneen I/O:n näyttäminen ESXi Dashboardissa

Alla olevassa tapauksessa Runspace ei ole enää hyödyllinen:

”Yritän kirjoittaa skriptiä, joka kerää paljon dataa VM:ltä ja kirjoittaa tarvittaessa uutta dataa. Ongelmana on, että VM:itä on melko paljon ja 5-8 sekuntia kuluu yhdellä koneella." 

Lähde: Monisäikeinen PowerCLI RunspacePoolilla

Täällä tarvitset Get-View'n, siirrytään siihen. 

Toinen vaihe: Get-View

Ymmärtääksesi, miksi Get-View on hyödyllinen, on syytä muistaa, miten cmdletit toimivat yleensä. 

Cmdlet-komentoja tarvitaan tiedon hankkimiseen kätevästi ilman, että sinun tarvitsee tutkia API-viitekirjoja ja keksiä uutta pyörää. Se, mikä vanhaan aikaan vaati sata tai kaksi koodiriviä, PowerShell antaa sinun tehdä yhdellä komennolla. Maksamme tästä mukavuudesta nopeudella. Itse cmdlettien sisällä ei ole taikuutta: sama kirjoitus, mutta alemmalla tasolla, aurinkoisesta Intiasta kotoisin olevan mestarin taitavien käsien kirjoittama.

Otetaan nyt Get-View'n vertailua varten Get-VM-cmdlet: se käyttää virtuaalikonetta ja palauttaa yhdistelmäobjektin, eli se liittää siihen muita asiaan liittyviä objekteja: VMHost, Datastore jne.  

Get-View ei lisää palautettuun objektiin mitään tarpeetonta. Lisäksi sen avulla voimme tiukasti määrittää, mitä tietoja tarvitsemme, mikä helpottaa tulosteobjektia. Windows Serverissä yleensä ja erityisesti Hyper-V:ssä Get-WMIObject-cmdlet on suora analoginen - idea on täsmälleen sama.

Get-View on hankala pisteobjektien rutiinitoimintoihin. Mutta kun on kyse tuhansista ja kymmenistä tuhansista esineistä, sillä ei ole hintaa.

Voit lukea lisää VMware-blogista: Get-View'n esittely

Nyt näytän sinulle kaiken todellisen kotelon avulla. 

Komentosarjan kirjoittaminen VM:n purkamiseksi

Eräänä päivänä kollegani pyysi minua optimoimaan hänen käsikirjoituksensa. Tehtävä on yleinen rutiini: etsi kaikki virtuaalikoneet, joissa on kaksoiskappale cloud.uuid-parametrilla (kyllä, tämä on mahdollista kloonattaessa virtuaalikonetta vCloud Directorissa). 

Ilmeinen ratkaisu, joka tulee mieleen, on:

  1. Hanki luettelo kaikista virtuaalikoneista.
  2. Jäsennä lista jotenkin.

Alkuperäinen versio oli tämä yksinkertainen käsikirjoitus:

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

Kaikki on erittäin yksinkertaista ja selkeää. Sen voi kirjoittaa muutamassa minuutissa kahvitauon kanssa. Ruuvaa suodatin kiinni ja se on valmis.

Mutta mitataan aika:

Rakettivahvistimen rakentaminen PowerCLI-skripteille

Rakettivahvistimen rakentaminen PowerCLI-skripteille

2 minuuttia 47 sekuntia kun käsitellään lähes 10 XNUMX virtuaalikonetta. Bonuksena on suodattimien puuttuminen ja tarve lajitella tulokset manuaalisesti. On selvää, että skripti vaatii optimoinnin.

Runspaces on ensimmäinen, joka tulee apuun, kun tarvitset samanaikaisesti isäntämittareita vCenteristä tai joudut käsittelemään kymmeniä tuhansia objekteja. Katsotaan mitä tämä lähestymistapa tuo tullessaan.

Ota käyttöön ensimmäinen nopeus: PowerShell Runspaces

Ensimmäinen asia, joka tulee mieleen tästä skriptistä, on suorittaa silmukka ei peräkkäin, vaan rinnakkaisissa säikeissä, kerätä kaikki tiedot yhteen objektiin ja suodattaa se. 

Mutta on ongelma: PowerCLI ei salli meidän avata monia itsenäisiä istuntoja vCenteriin ja antaa hauskan virheen:

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.

Tämän ratkaisemiseksi sinun on ensin välitettävä istuntotiedot streamin sisällä. Muistakaamme, että PowerShell toimii objektien kanssa, jotka voidaan välittää parametreina joko funktiolle tai ScriptBlockille. Välitetään istunto tällaisen objektin muodossa ohittaen $global:DefaultVIServers (Connect-VIServer -NotDefault-avaimella):

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

Toteutetaan nyt monisäikeisyys Runspace Poolsin kautta.  

Algoritmi on seuraava:

  1. Saamme luettelon kaikista virtuaalikoneista.
  2. Rinnakkaisvirroissa saamme cloud.uuid.
  3. Keräämme dataa virroista yhteen objektiin.
  4. Suodatamme objektin ryhmittelemällä sen CloudUUID-kentän arvon mukaan: ne, joissa yksilöllisten arvojen määrä on suurempi kuin 1, ovat etsimiämme VM:itä.

Tuloksena saamme käsikirjoituksen:


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
}

Tämän skriptin kauneus on, että sitä voidaan käyttää muissa vastaavissa tapauksissa yksinkertaisesti korvaamalla ScriptBlock ja parametrit, jotka välitetään streamiin. Hyödynnä sitä!

Mittaamme ajan:

Rakettivahvistimen rakentaminen PowerCLI-skripteille

55 sekuntia. Se on parempi, mutta se voi silti olla nopeampi. 

Siirrytään toiseen nopeuteen: GetView

Selvitetään mikä on vialla.
Ensinnäkin Get-VM-cmdletin suorittaminen kestää kauan.
Toiseksi Get-AdvancedOptions-cmdletin valmistuminen kestää vielä kauemmin.
Käsitellään ensin toista. 

Get-AdvancedOptions on kätevä yksittäisille VM-objekteille, mutta erittäin kömpelö monien objektien kanssa työskenneltäessä. Voimme saada samat tiedot itse virtuaalikoneen objektista (Get-VM). Se on vain hyvin haudattu ExtensionData-objektiin. Suodatuksen avulla nopeutamme tarvittavien tietojen hankintaa.

Pienellä käden liikkeellä tämä on:


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

Muuttuu tälläiseksi:


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

Tulos on sama kuin Get-AdvancedOptions, mutta se toimii monta kertaa nopeammin. 

Nyt Get-VM:ään. Se ei ole nopea, koska se käsittelee monimutkaisia ​​esineitä. Herää looginen kysymys: miksi tarvitsemme tässä tapauksessa lisätietoa ja hirviömäisen PSO-objektin, kun tarvitsemme vain VM:n nimen, sen tilan ja hankalan attribuutin arvon?  

Lisäksi skriptistä on poistettu este Get-AdvancedOptions-muodossa. Runspace Poolsin käyttäminen näyttää nyt ylivoimaiselta, koska ei enää tarvitse rinnastaa hidasta tehtävää squat-säikeiden välillä istuntoa luovutettaessa. Työkalu on hyvä, mutta ei tähän tapaukseen. 

Katsotaanpa ExtensionDatan tulosta: se ei ole muuta kuin Get-View-objekti. 

Otetaan käyttöön PowerShell-mestarien ikivanha tekniikka: yksi rivi suodattimia, lajittelua ja ryhmittelyä käyttäen. Kaikki edellinen kauhu on tiivistetty tyylikkäästi yhdeksi riviksi ja toteutettu yhdessä istunnossa:


$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

Mittaamme ajan:

Rakettivahvistimen rakentaminen PowerCLI-skripteille

9 sekuntia lähes 10 XNUMX kohteelle suodatuksella halutun ehdon mukaan. Loistava!

Sen sijaan johtopäätös

Hyväksyttävä tulos riippuu suoraan työkalun valinnasta. Usein on vaikea sanoa varmasti, mitä tarkalleen pitäisi valita sen saavuttamiseksi. Jokainen luetelluista menetelmistä skriptien nopeuttamiseksi on hyvä soveltuvuuden rajoissa. Toivon, että tämä artikkeli auttaa sinua vaikeassa tehtävässä ymmärtää infrastruktuurisi prosessiautomaation ja optimoinnin perusteet.

PS: Kirjoittaja kiittää kaikkia yhteisön jäseniä avusta ja tuesta artikkelin valmistelussa. Jopa ne, joilla on tassut. Ja jopa ne, joilla ei ole jalkoja, kuten boa constrictor.

Lähde: will.com

Lisää kommentti