PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar 

Gec və ya tez istənilən VMware sistem administratoru rutin tapşırıqları avtomatlaşdırmağa gəlir. Hamısı komanda xətti ilə başlayır, sonra PowerShell və ya VMware PowerCLI gəlir.

Deyək ki, siz PowerShell-i ISE-ni işə salmaqdan və "bir növ sehr" vasitəsilə işləyən modullardan standart cmdletlərdən istifadə etməklə bir az daha çox mənimsəmisiniz. Yüzlərlə virtual maşını saymağa başladıqda, kiçik miqyasda kömək edən skriptlərin böyük birində nəzərəçarpacaq dərəcədə yavaş işlədiyini görəcəksiniz. 

Bu vəziyyətdə 2 vasitə kömək edəcək:

  • PowerShell İstifadə Sahələri – ayrı-ayrı iplərdə proseslərin icrasını paralelləşdirməyə imkan verən yanaşma; 
  • görünüş əldə etmək - Windows-da Get-WMIObject analoqu olan PowerCLI-nin əsas funksiyası. Bu cmdlet əlaqəli obyekt obyektlərini çəkmir, əksinə məlumatı sadə məlumat növləri ilə sadə obyekt kimi qəbul edir. Bir çox hallarda daha tez çıxır.

Sonra, hər bir alət haqqında qısaca danışacağam və istifadə nümunələrini göstərəcəyəm. Gəlin konkret skriptləri təhlil edək və görək biri nə vaxt daha yaxşı, ikincisi nə vaxt işləyir. Get!

PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar

Birinci Mərhələ: Qaçış

Beləliklə, Runspace əsas moduldan kənar tapşırıqların paralel işlənməsi üçün nəzərdə tutulmuşdur. Əlbəttə ki, siz bəzi yaddaş, prosessor və s. yeyəcək başqa bir prosesə başlaya bilərsiniz. Əgər skriptiniz bir neçə dəqiqə ərzində işləyirsə və gigabayt yaddaş sərf edirsə, çox güman ki, sizə Runspace lazım olmayacaq. Ancaq on minlərlə obyekt üçün skriptlər üçün bu lazımdır.

Buradan öyrənməyə başlaya bilərsiniz: 
PowerShell İstifadə Sahələrinin İstifadəyə Başlanması: 1-ci Hissə

Runspace-dən istifadəni nə təmin edir:

  • icra edilə bilən əmrlərin siyahısını məhdudlaşdırmaqla sürət,
  • tapşırıqların paralel icrası,
  • təhlükəsizlik.

Runspace-in kömək etdiyi internetdən bir nümunə:

“Yaddaş mübahisəsi vSphere-də izləmək üçün ən çətin ölçülərdən biridir. VCenter daxilində siz gedib hansı VM-nin daha çox yaddaş resursları istehlak etdiyini görə bilməzsiniz. Xoşbəxtlikdən, PowerShell ilə bu məlumatları bir neçə dəqiqə ərzində toplaya bilərsiniz.
Mən VMware sistem administratorlarına bütün vCenter-də tez axtarış aparmağa və onların orta istehlak məlumatları ilə VM-lərin siyahısını əldə etməyə imkan verəcək skript paylaşacağam.  
Skript PowerShell iş yerlərindən istifadə edir ki, hər bir ESXi hostu ayrı Runspace-də öz VM-lərinin istehlakı haqqında məlumat toplayır və dərhal tamamlanma haqqında məlumat verir. Bu, PowerShell-ə ​​hostlar vasitəsilə təkrarlamaq və hər birinin öz sorğusunu tamamlamasını gözləmək əvəzinə, işləri dərhal bağlamağa imkan verir.”

Mənbə: ESXi İdarə Panelində Virtual Maşın I/O-nu necə göstərmək olar

Aşağıdakı halda, Runspace işləmir:

“Mən VM-dən çoxlu məlumat toplayan və lazım gələrsə yeni məlumatlar yazan skript yazmağa çalışıram. Problem ondadır ki, kifayət qədər çoxlu VM var və bir maşın üçün bu, 5-8 saniyə çəkir”. 

Mənbə: RunspacePool ilə çox iş parçacığı PowerCLI

Get-View burada lazımdır, ona keçək. 

İkinci addım: Get-View

Get-View-in necə faydalı olduğunu başa düşmək üçün ümumiyyətlə cmdletlərin necə işlədiyini xatırlamağa dəyər. 

Cmdletlər API istinadlarını öyrənmədən və növbəti təkəri yenidən kəşf etmədən rahat şəkildə məlumat əldə etmək üçün lazımdır. Köhnə günlərdə yüz və ya iki sətir kodda yazılmışdı, PowerShell bunu bir əmrlə etməyə imkan verir. Biz bu rahatlığın əvəzini sürətlə ödəyirik. Cmdletlərin özündə heç bir sehr yoxdur: eyni ssenari, lakin günəşli Hindistandan olan ustanın bacarıqlı əlləri ilə yazılmış daha aşağı səviyyəli.

İndi Get-View ilə müqayisə üçün Get-VM cmdletini götürək: o, virtual maşına daxil olur və kompozit obyekti qaytarır, yəni ona digər əlaqəli obyektləri əlavə edir: VMHost, Datastore və s.  

Get-View öz yerində geri qaytarılan obyektə əlavə heç bir şey bağlamır. Üstəlik, bu, bizə lazım olan məlumatları sərt kodlamağa imkan verir ki, bu da bir obyekti çıxarmağı asanlaşdıracaq. Ümumiyyətlə Windows Server-də və xüsusilə Hyper-V-də Get-WMIObject cmdlet birbaşa analoqdur - ideya tamamilə eynidir.

Get-View nöqtə obyektləri üzərində adi əməliyyatlarda əlverişsizdir. Minlərlə, on minlərlə obyektə gəlincə, bunun qiyməti yoxdur.

VMware bloqunda daha çox oxuyun: Get-View tətbiqinə giriş

İndi hər şeyi real bir işdə göstərəcəyəm. 

VM-i boşaltmaq üçün skriptin yazılması

Bir gün həmkarım məndən onun ssenarisini optimallaşdırmağı xahiş etdi. Tapşırıq adi işdir: dublikat cloud.uuid parametri olan bütün VM-ləri tapın (bəli, bu, vCloud Director-də VM-nin klonlanması zamanı mümkündür). 

Ağlına gələn açıq həll yolu:

  1. Bütün VM-lərin siyahısını əldə edin.
  2. Siyahını birtəhər təhlil edin.

Orijinal versiya belə sadə bir ssenari idi:

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

Hər şey son dərəcə sadə və aydındır. Kofe fasiləsi ilə bir neçə dəqiqəyə yazılmışdır. Süzgəci sıxın və hazırdır.

Amma gəlin vaxta nəzər salaq:

PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar

PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar

2 dəqiqə 47 saniyə demək olar ki, 10k VM-ni emal edərkən. Bonus filtrlərin olmaması və nəticəni əl ilə çeşidləmək ehtiyacıdır. Skriptin optimallaşdırmaya ehtiyacı olduğu aydındır.

Bir anda vCenter-dən host ölçülərini əldə etməli olduğunuzda və ya on minlərlə obyekti emal etməli olduğunuzda ilk olaraq Runspaces köməyə gəlir. Bu yanaşmanın nə verdiyini görək.

İlk sürəti yandırmaq: PowerShell Runspaces

Bu skript üçün ilk ağıla gələn döngəni ardıcıl olaraq deyil, paralel axınlarda yerinə yetirmək, bütün məlumatları bir obyektə toplamaq və filtr etməkdir. 

Ancaq bir problem var: PowerCLI bizə vCenter-də bir çox müstəqil seans açmağa icazə verməyəcək və gülməli bir səhv atacaq:

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.

Bunu həll etmək üçün əvvəlcə seans haqqında məlumatı ipin daxilində ötürməliyik. Xatırlayırıq ki, PowerShell hətta funksiyaya, hətta ScriptBlock-a parametr kimi ötürülə bilən obyektlərlə işləyir. Gəlin $global:DefaultVIServers (-NotDefault düyməsi ilə Connect-VIServer)-dan yan keçərək sessiyanı belə bir obyekt kimi keçirək:

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

İndi biz Runspace Pools vasitəsilə multithreading həyata keçiririk.  

Alqoritm aşağıdakı kimidir:

  1. Bütün VM-lərin siyahısını alırıq.
  2. Paralel axınlarda biz cloud.uuid əldə edirik.
  3. Biz axınlardan məlumatları bir obyektə toplayırıq.
  4. CloudUUID sahəsinin dəyərinə görə qruplaşdıraraq obyekti süzgəcdən keçiririk: unikal dəyərlərin sayı 1-dən çox olanlar istənilən VM-lərdir.

Nəticədə skript alırıq:


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
}

Bu skriptin gözəlliyi ondan ibarətdir ki, o, sadəcə olaraq ScriptBlock-u və axına ötürüləcək parametrləri əvəz etməklə digər oxşar hallarda istifadə oluna bilər. İstifadə et!

Zamanı ölçürük:

PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar

55 saniyə. Onsuz da daha yaxşı, amma yenə də daha sürətli. 

İkinci sürətə keçid: GetView

Gəlin nəyin səhv olduğunu öyrənək.
Birincisi və aydındır ki, Get-VM cmdletini tamamlamaq çox vaxt aparır.
İkincisi, Get-AdvancedOptions cmdletinin tamamlanması daha uzun çəkir.
Əvvəlcə ikinci ilə məşğul olaq. 

Get-AdvancedOptions fərdi VM obyektlərində əlverişlidir, lakin çoxsaylı obyektlərlə işləyərkən çox yöndəmsizdir. Eyni məlumatı virtual maşın obyektinin (Get-VM) özündən əldə edə bilərik. ExtensionData obyektində sadəcə yaxşı basdırılıb. Filtrləmə ilə silahlanmış, biz lazımi məlumatların əldə edilməsi prosesini sürətləndiririk.

Bir bilək hərəkəti ilə bu:


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

Buna çevrilir:


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

Çıxış Get-AdvancedOptions ilə eynidir, lakin daha sürətlidir. 

İndi Get-VM-ə keçin. Mürəkkəb obyektlərlə məşğul olduğu üçün sürətli deyil. Məntiqi sual yaranır: bizə sadəcə VM-nin adına, onun vəziyyətinə və çətin atributun dəyərinə ehtiyacımız olduğu halda, bu halda nə üçün bizə əlavə məlumat və dəhşətli PSObject lazımdır?  

Bundan əlavə, Get-AdvancedOptions qarşısında əyləc skriptdən getdi. Runspace Pools-un istifadəsi indi həddən artıq iş kimi görünür, çünki artıq seans köçürmə squats ilə mövzularda yavaş tapşırığı paralelləşdirməyə ehtiyac yoxdur. Alət yaxşıdır, amma bu vəziyyət üçün deyil. 

ExtensionData-nın çıxışına baxırıq: bu Get-View obyektindən başqa bir şey deyil. 

PowerShell sehrbazlarının qədim texnikasına müraciət edək: filtrlərdən istifadə edən bir xətt, çeşidləmə və qruplaşdırma. Bütün əvvəlki dəhşətlər zərif şəkildə bir xəttə yığılır və bir seansda icra olunur:


$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

Zamanı ölçürük:

PowerCLI skriptləri üçün raket gücləndiricisini necə qurmaq olar

9 saniyə demək olar ki, 10k obyekt üçün istənilən şəraitə görə filtrasiya. Əla!

Bunun əvəzinə bir nəticəyə

Məqbul nəticə birbaşa alət seçimindən asılıdır. Buna nail olmaq üçün dəqiq nəyin seçilməli olduğunu dəqiq söyləmək çox vaxt çətindir. Skriptləri sürətləndirmək üçün yuxarıda göstərilən üsulların hər biri tətbiq olunma imkanları daxilində yaxşıdır. Ümid edirəm ki, bu məqalə prosesin avtomatlaşdırılmasının əsaslarını başa düşmək və onları infrastrukturunuzda optimallaşdırmaq kimi çətin işdə sizə kömək edəcəkdir.

PS: Müəllif məqalənin hazırlanmasında göstərdikləri köməyə və dəstəyə görə kommunanın bütün üzvlərinə təşəkkür edir. Hətta pəncələri olanlar da. Hətta pəncələri olmayanlar da boa konstriktoru kimi.

Mənbə: www.habr.com

Добавить комментарий