Ինչպես ստեղծել հրթիռային ուժեղացուցիչ PowerCLI սկրիպտների համար 

Վաղ թե ուշ ցանկացած VMware համակարգի ադմինիստրատոր գալիս է ավտոմատացնելու սովորական առաջադրանքները: Ամեն ինչ սկսվում է հրամանի տողից, հետո գալիս է PowerShell կամ VMware PowerCLI:

Ենթադրենք, դուք տիրապետել եք PowerShell-ին մի փոքր ավելի հեռու, քան ISE-ն գործարկելը և ստանդարտ cmdlet-ներ օգտագործել մոդուլներից, որոնք աշխատում են «ինչ-որ մոգության» շնորհիվ: Երբ սկսում եք վիրտուալ մեքենաները հարյուրներով հաշվել, կտեսնեք, որ փոքր մասշտաբով օգնող սկրիպտները մեծ մասշտաբով զգալիորեն դանդաղ են աշխատում: 

Այս իրավիճակում 2 գործիքներ կօգնեն.

  • PowerShell Runspaces – մոտեցում, որը թույլ է տալիս զուգահեռացնել գործընթացների կատարումը առանձին թելերով. 
  • Ստանալ-Դիտել – հիմնական PowerCLI ֆունկցիան, Windows-ում Get-WMIObject-ի անալոգը: Այս cmdlet-ը չի քաշում ուղեկցող օբյեկտները, այլ տեղեկատվություն է ստանում պարզ օբյեկտի տեսքով՝ տվյալների պարզ տեսակներով: Շատ դեպքերում այն ​​ավելի արագ է դուրս գալիս։

Հաջորդը, ես համառոտ կխոսեմ յուրաքանչյուր գործիքի մասին և ցույց կտամ օգտագործման օրինակներ: Եկեք վերլուծենք կոնկրետ սցենարներ և տեսնենք, թե երբ է մեկը մյուսից լավ աշխատում: Գնա՛

Ինչպես ստեղծել հրթիռային ուժեղացուցիչ PowerCLI սկրիպտների համար

Առաջին փուլ. Runspace

Այսպիսով, Runspace-ը նախատեսված է հիմնական մոդուլից դուրս առաջադրանքների զուգահեռ մշակման համար։ Իհարկե, դուք կարող եք գործարկել մեկ այլ պրոցես, որը կխլի որոշակի հիշողություն, պրոցեսոր և այլն: Եթե ձեր սկրիպտը գործարկվի մի քանի րոպեում և սպառի մեկ գիգաբայթ հիշողություն, ամենայն հավանականությամբ ձեզ Runspace-ը պետք չի լինի: Բայց տասնյակ հազարավոր օբյեկտների սցենարների համար դա անհրաժեշտ է։

Դուք կարող եք սկսել սովորել այստեղ. 
PowerShell Runspaces-ի սկիզբ. Մաս 1

Ի՞նչ է տալիս Runspace-ի օգտագործումը.

  • արագություն՝ սահմանափակելով կատարված հրամանների ցանկը,
  • առաջադրանքների զուգահեռ կատարում,
  • անվտանգություն:

Ահա մի օրինակ ինտերնետից, երբ Runspace-ն օգնում է.

«Պահպանման վեճը vSphere-ում հետևելու ամենադժվար ցուցանիշներից մեկն է: vCenter-ի ներսում դուք պարզապես չեք կարող գնալ և տեսնել, թե որ VM-ն է ավելի շատ պահեստավորման ռեսուրսներ սպառում: Բարեբախտաբար, դուք կարող եք հավաքել այս տվյալները րոպեների ընթացքում PowerShell-ի շնորհիվ:
Ես կկիսվեմ մի սկրիպտով, որը VMware համակարգի ադմինիստրատորներին թույլ կտա արագ որոնել vCenter-ում և ստանալ VM-ների ցուցակը՝ դրանց միջին սպառման վերաբերյալ տվյալներով:  
Սկրիպտը օգտագործում է PowerShell-ի աշխատատեղերը, որպեսզի յուրաքանչյուր ESXi հոսթին կարողանա հավաքել սպառման մասին տեղեկատվություն իր VM-ներից առանձին Runspace-ում և անմիջապես հաղորդել ավարտի մասին: Սա PowerShell-ին թույլ է տալիս անմիջապես փակել աշխատանքները, այլ ոչ թե կրկնել հոսթինգների միջոցով և սպասել, որ յուրաքանչյուրն ավարտի իր հարցումը»:

Source: Ինչպես ցուցադրել վիրտուալ մեքենայի մուտք/ելք ESXi վահանակի վրա

Ստորև բերված դեպքում Runspace-ն այլևս օգտակար չէ.

«Ես փորձում եմ գրել մի սցենար, որը հավաքում է շատ տվյալներ VM-ից և անհրաժեշտության դեպքում գրում է նոր տվյալներ: Խնդիրն այն է, որ VM-ները բավականին շատ են, իսկ մեկ մեքենայի վրա ծախսվում է 5-8 վայրկյան»։ 

Source: Multithreading PowerCLI RunspacePool-ով

Այստեղ ձեզ անհրաժեշտ կլինի Get-View, եկեք անցնենք դրան: 

Երկրորդ փուլ՝ Get-View

Հասկանալու համար, թե ինչու է Get-View-ն օգտակար, արժե հիշել, թե ինչպես են աշխատում cmdlet-ները ընդհանրապես: 

Cmdlet-ներն անհրաժեշտ են տեղեկատվություն ստանալու համար՝ առանց API-ի տեղեկատու գրքերն ուսումնասիրելու և հաջորդ անիվը նորից հայտնագործելու անհրաժեշտության: Այն, ինչ հին ժամանակներում պահանջում էր հարյուր կամ երկու տող կոդ, PowerShell-ը թույլ է տալիս անել մեկ հրամանով: Մենք վճարում ենք այս հարմարության համար արագությամբ: Ինքը՝ cmdlet-ների ներսում ոչ մի կախարդանք չկա. նույն սցենարը, բայց ավելի ցածր մակարդակի վրա, գրված է արևոտ Հնդկաստանից վարպետի հմուտ ձեռքերով:

Այժմ Get-View-ի հետ համեմատելու համար վերցնենք Get-VM cmdlet-ը. այն մուտք է գործում վիրտուալ մեքենա և վերադարձնում կոմպոզիտային օբյեկտ, այսինքն՝ դրան կցում է այլ առնչվող օբյեկտներ՝ VMHost, Datastore և այլն:  

Get-View-ն իր տեղում ավելորդ ոչինչ չի ավելացնում վերադարձված օբյեկտին։ Ավելին, դա մեզ թույլ է տալիս խստորեն նշել, թե ինչ տեղեկատվություն է մեզ անհրաժեշտ, ինչը կհեշտացնի ելքային օբյեկտը։ Windows Server-ում ընդհանրապես և Hyper-V-ում, մասնավորապես, Get-WMIObject cmdlet-ը ուղղակի անալոգ է. գաղափարը նույնն է:

Get-View-ը անհարմար է կետային օբյեկտների վրա սովորական գործողությունների համար: Բայց երբ խոսքը գնում է հազարավոր ու տասնյակ հազարավոր օբյեկտների մասին, դա գին չունի։

Ավելին կարող եք կարդալ VMware բլոգում. Ներածություն Get-View-ում

Այժմ ես ձեզ ցույց կտամ ամեն ինչ՝ օգտագործելով իրական պատյան: 

VM-ը բեռնաթափելու համար սցենար գրելը

Մի օր գործընկերս ինձ խնդրեց օպտիմալացնել իր սցենարը: Առաջադրանքը սովորական առօրյա է՝ գտնել բոլոր VM-ները կրկնօրինակ cloud.uuid պարամետրով (այո, դա հնարավոր է 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 վայրկյան գրեթե 10 հազար 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 $_
           }
       }
   }

Այժմ եկեք իրականացնենք multithreading-ը 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 cmdlet-ի գործարկումը երկար ժամանակ է պահանջում:
Երկրորդ, Get-AdvancedOptions cmdlet-ի ավարտը ավելի երկար է տևում:
Նախ անդրադառնանք երկրորդին։ 

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-ին: Այն արագ չէ, քանի որ գործ ունի բարդ օբյեկտների հետ: Տրամաբանական հարց է առաջանում՝ այս դեպքում մեզ ինչի՞ն է պետք հավելյալ տեղեկատվություն և հրեշավոր PSO-օբյեկտ, երբ մեզ պարզապես անհրաժեշտ է VM-ի անունը, նրա վիճակը և խրթին հատկանիշի արժեքը։  

Բացի այդ, սցենարից հանվել է Get-AdvancedOptions-ի տեսքով խոչընդոտը։ Runspace Pools-ի օգտագործումն այժմ չափազանցված է թվում, քանի որ նիստը հանձնելիս այլևս կարիք չկա դանդաղ առաջադրանքը զուգահեռեցնել squat threads-ով: Գործիքը լավն է, բայց ոչ այս դեպքի համար: 

Եկեք նայենք 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 վայրկյան գրեթե 10 հազար օբյեկտների համար, որոնք զտվում են ըստ ցանկալի վիճակի: Հիանալի

Փոխարենը մի եզրակացության

Ընդունելի արդյունքն ուղղակիորեն կախված է գործիքի ընտրությունից: Հաճախ դժվար է հստակ ասել, թե կոնկրետ ինչ պետք է ընտրել դրան հասնելու համար։ Սկրիպտների արագացման թվարկված մեթոդներից յուրաքանչյուրը լավ է իր կիրառելիության սահմաններում: Հուսով եմ, որ այս հոդվածը կօգնի ձեզ ձեր ենթակառուցվածքում գործընթացների ավտոմատացման և օպտիմալացման հիմունքները հասկանալու դժվարին գործում:

PS: Հեղինակը շնորհակալություն է հայտնում համայնքի բոլոր անդամներին հոդվածի պատրաստման հարցում ցուցաբերած օգնության և աջակցության համար: Նույնիսկ թաթիկներով: Եվ նույնիսկ նրանք, ովքեր ոտքեր չունեն, ինչպես բոա կոնստրուկտորը:

Source: www.habr.com

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