PowerCLI スクリプト甚のロケット ブヌスタヌを構築する方法 

遅かれ早かれ、VMware システム管理者は日垞的なタスクを自動化するようになりたす。 すべおはコマンド ラむンから始たり、次に PowerShell たたは VMware PowerCLI が登堎したす。

ISE を起動し、「ある皮の魔法」によっお機胜するモゞュヌルから暙準コマンドレットを䜿甚するよりも少し進んで PowerShell をマスタヌしたずしたす。 仮想マシンを数癟台単䜍で数え始めるず、小芏暡では圹立぀スクリプトが、倧芏暡では実行が著しく遅くなるこずがわかりたす。 

この状況では、次の 2 ぀のツヌルが圹に立ちたす。

  • PowerShell 実行スペヌス – 別々のスレッドでプロセスの実行を䞊列化できるアプロヌチ。 
  • 取埗ビュヌ – 基本的な PowerCLI 関数。Windows の Get-WMIObject に盞圓したす。 このコマンドレットぱンティティに付随するオブゞェクトを取埗したせんが、単玔なデヌタ型を持぀単玔なオブゞェクトの圢匏で情報を受け取りたす。 倚くの堎合、その方が早く出おきたす。

次に、各ツヌルに぀いお簡単に説明し、䜿甚䟋を瀺したす。 特定のスクリプトを分析しお、䞀方のスクリプトが他方のスクリプトよりもうたく動䜜するかどうかを確認しおみたしょう。 行く

PowerCLI スクリプト甚のロケット ブヌスタヌを構築する方法

最初のステヌゞ: ランスペヌス

そのため、Runspace はメむン モゞュヌルの倖偎でタスクを䞊列凊理できるように蚭蚈されおいたす。 もちろん、メモリやプロセッサなどを消費する別のプロセスを起動するこずもできたす。スクリプトが数分で実行され、ギガバむトのメモリを消費する堎合は、おそらく Runspace は必芁ありたせん。 ただし、数䞇のオブゞェクト甚のスクリプトの堎合は必芁です。

ここから孊習を始めるこずができたす。 
PowerShell 実行空間の䜿甚を開始する: パヌト 1

Runspace を䜿甚するず次のこずが埗られたす。

  • 実行されるコマンドのリストを制限するこずで速床を向䞊させたす。
  • タスクの䞊列実行、
  • 安党

Runspace が圹立぀むンタヌネットの䟋を次に瀺したす。

「ストレヌゞ競合は、vSphere で远跡するのが最も難しい指暙の XNUMX ぀です。 vCenter 内では、どの VM がより倚くのストレヌゞ リ゜ヌスを消費しおいるかをただ確認するこずはできたせん。 幞いなこずに、PowerShell のおかげで、このデヌタは数分で収集できたす。
VMware システム管理者が vCenter 党䜓をすばやく怜玢し、平均消費量に関するデヌタを含む VM のリストを取埗できるようにするスクリプトを共有したす。  
このスクリプトは PowerShell 実行空間を䜿甚しお、各 ESXi ホストが個別の実行空間内の独自の VM から消費情報を収集し、すぐに完了を報告できるようにしたす。 これにより、PowerShell はホストを反埩凊理しお各ホストが芁求を完了するのを埅぀こずなく、ゞョブをすぐに閉じるこずができたす。」

出所 ESXi ダッシュボヌドに仮想マシン I/O を衚瀺する方法

以䞋の堎合、Runspace は圹に立ちたせん。

「VM から倧量のデヌタを収集し、必芁に応じお新しいデヌタを曞き蟌むスクリプトを䜜成しようずしおいたす。 問題は、VM が非垞に倚く、5 台のマシンに 8  XNUMX 秒かかるこずです。」 

出所 RunspacePool を䜿甚したマルチスレッド PowerCLI

ここで Get-View が必芁になりたす。次に進みたしょう。 

第 XNUMX 段階: Get-View

Get-View がなぜ圹立぀のかを理解するには、コマンドレットが䞀般的にどのように機胜するかを芚えおおく䟡倀がありたす。 

コマンドレットは、API リファレンス ブックを読んで次の車茪を再発明するこずなく、情報を簡単に取埗するために必芁です。 以前は XNUMX  XNUMX 行のコヌドが必芁でしたが、PowerShell を䜿甚するず XNUMX ぀のコマンドで実行できるようになりたす。 私たちはこの利䟿性に察しお迅速な察䟡を支払いたす。 コマンドレット自䜓の内郚には魔法はありたせん。同じスクリプトですが、より䜎いレベルで、倪陜が降り泚ぐむンドの達人の熟緎した手によっお曞かれおいたす。

ここで、Get-View ず比范するために、Get-VM コマンドレットを芋おみたしょう。このコマンドレットは仮想マシンにアクセスし、耇合オブゞェクトを返したす。぀たり、他の関連オブゞェクト (VMHost、Datastore など) を仮想マシンにアタッチしたす。  

Get-View を代わりに䜿甚するず、返されたオブゞェクトに䞍必芁なものは䜕も远加されたせん。 さらに、必芁な情報を厳密に指定できるため、出力オブゞェクトが簡単になりたす。 Windows Server 党般、特に 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秒 箄 10 個の VM を凊理する堎合。 利点は、フィルタヌがないこずず、結果を手動で䞊べ替える必芁がないこずです。 明らかに、スクリプトには最適化が必芁です。

実行空間は、vCenter からホスト メトリックを同時に取埗する必芁がある堎合、たたは数䞇のオブゞェクトを凊理する必芁がある堎合に、最初に圹に立ちたす。 このアプロヌチが䜕をもたらすかを芋おみたしょう。

最初の速床をオンにする: PowerShell ランスペヌス

このスクリプトで最初に思い぀くのは、ルヌプを順次ではなく䞊列スレッドで実行し、すべおのデヌタを XNUMX ぀のオブゞェクトに収集しおフィルタヌ凊理するこずです。 

しかし、問題がありたす。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 (-NotDefault キヌを䜿甚しお Connect-VIServer) をバむパスしお、このようなオブゞェクトの圢匏でセッションを枡したしょう。

$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. ストリヌムからのデヌタを XNUMX ぀のオブゞェクトに収集したす。
  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秒。 改善されたしたが、それでもさらに高速になる可胜性がありたす。 

XNUMX 番目の速床に移りたしょう: GetView

䜕が問題なのか調べおみたしょう。
䜕よりもたず、Get-VM コマンドレットの実行には時間がかかりたす。
次に、Get-AdvancedOptions コマンドレットの完了にはさらに時間がかかりたす。
たず XNUMX 番目のこずに察凊したしょう。 

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 マスタヌの叀代のテクニック、぀たりフィルタヌ、䞊べ替え、グルヌプ化を䜿甚した XNUMX 行を䜿っおみたしょう。 これたでの恐怖はすべお XNUMX 行に゚レガントにたずめられ、XNUMX ぀のセッションで実行されたす。


$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 著者は、蚘事の準備にあたり、コミュニティ メンバヌの皆様のご協力ずご協力に感謝いたしたす。 足のある人でも。 ボアコンストリクタヌのように足のない人でも。

出所 habr.com

コメントを远加したす