**** 留意事項 *****
こちらのブログの内容はDECN(Dell EMC Community Network)に投稿されたブログの再掲です。
DECNが近い将来に廃止となるためこちらに移行させていただいております。
内容についてはオリジナルの執筆当時のものとなりますので最新ではない場合がありますがご容赦ください。
本記事ではPowerCLIのMove-VMコマンドレットを利用したVM移行で使えそうなコマンドについて紹介します。
前回までの記事は以下です。
既存環境からvSAN 環境へのMigration:その① 【イントロダクション】
既存環境からvSAN 環境へのMigration:その② 【PowerCLIのInstall】
既存環境からvSAN 環境へのMigration:その③ 【既存環境からのvMotion】
本シリーズは、PowerCLIを利用した独立vSAN環境へのvMotionの基礎を紹介するところまでで終わるつもりでしたが、
実際にラボ環境で移行を試したところ、もうちょっと便利で手軽に移行したい!という気持ちになったので複数がてら投稿することにしました。
##### 留意事項 ######
本記事で使用する変数(non-vxrailVCやvxrailVC)は前回までで使用した変数を引き継いでいます。
################
前回に紹介したコマンドでは以下のことが可能でした。
・単体VMのvMotion
・VM名でフィルターしたVM Listの一括vMotion
しかし、実際の移行の現場では単体VMのvMotionを手動で何度も実施するのは手間ですし、
VM名でVMをグループ分けしている環境のほうが珍しいかもしれません。
また、前回紹介した一括vMotionの方法では、複数のVMを単一ホストに移行することしかできず、分散するためには何度かに分けて実行しなくてはいけません。
しかも宛先のPortGroupを指定する必要があるため単体VM or VM group毎に、使用するPortGroupを手動でしらべてコマンドを作らなければいけません。
しかも、複数vNIC/複数PortGroupを使用するVMを考慮していませんでした。
まとめると、前回までの内容では以下の欠点がありました。
・一括vMotionする際のVM グルーピングの粒度が雑
・一度に一つのホストしかvMotion先として選べない
・複数vNIC/複数PortGroupを持つVMの移行に対応していない
上記の欠点を解決するには以下の要素が必要でした。
・使用するPortGroup毎にVMをグルーピングして一括vMotionできるようにする
・宛先となるESXi ホストを分散する
・複数vNIC/複数PortGroupを持つVMであってもそれぞれ適切な宛先PortGroupを指定できるようにする
それでは上記課題を解決するコマンドを見てみましょう。
使用するPortGroup毎にVMをグルーピングして一括vMotionできるようにする
VMをグルーピングして変数に格納する方法はいくつか考えられます。たとえば
- VM名に含まれるキーワードでグルーピング
- $vms = Get-VM -Name *joe* ※名前にjoeを含むVM一覧を取得
- VMが所属するフォルダでグルーピング
- $vms = Get-Folder -Name kaneda | Get-VM ※kanedaフォルダに所属するVM一覧を取得
- VMが所属するリソースプールでグルーピング
- $vms = Get-ResourcePool -Name "ESX Agents" | Get-VM ※ESX Agents リソースグループに所属するVM一覧を取得
- VMが利用するPortGroupでグルーピング
- $vms = Get-VDPortgroup -Name vCenter* | Get-VM ※vCenter* ポートグループに含まれるVM一覧を取得
その他、HostベースでまとめるためにはGet-VMHostや、クラスタごとにまとめるGet-Clusterを利用した方法が考えられますが、今回の用途に一番適しているのはPortGroupでグルーピングする方法のように思えます。
各VMが単一のvNICしか持たないことが前提であればこれで済む話なのですが、今回は複数vNICやPortGroupをもつVMを対象としていますのでこの方法では不十分です。
例えば以下の要件を満たすVMの一覧を取得したい場合はどうしたらいいでしょうか?
・test フォルダに所属している
・vNICを二つ持ちそれぞれ別のポートグループに所属している
・一つのvNICはLAB ポートグループに所属している
・もう一つのvNICはvCenter Server Network-a5643020-0c6e-471b-8baf-6aa1021583b5 に所属している
いろいろな方法があるとは思いますが以下のアルゴリズムを考えました。
- ソース側のvSphere Clusterのtestフォルダに所属する全VMをリストする
- 1のリストのVMが持つvNICを取得する
- vNIC数が2つ、かつ対象のPortGroupの両方に所属にしているVM取得する
実際には以下のコマンドを使います
foreach ($vm in @((Get-Folder -Server non-vxrailVC -Name test | Get-VM))) {
$networkAdapters = (Get-Networkadapter -VM $vm) | Sort-Object -Property NetworkName
if ( (get-networkadapter -VM $vm | measure).count -eq 2 -And $networkAdapters.NetworkName.Contains("LAB") -And $networkAdapters.NetworkName.Contains("vCenter Server Network-a5643020-0c6e-471b-8baf-6aa1021583b5") ) {
<ここに処理を記述>
}
}
foreach文にフォルダでフィルターしたVMリストを渡してループを回しています。
ループの中で各VMのvNICを取得して、vNICの数と所属に一致するものだけを対象に処理を実施します。
コマンド中、赤く強調した部分がありますがこれの意味はあとでわかります。
一度に一つのホストしかvMotion先として選べない
これを実現するためには、Move-VMコマンドレットでの移行毎に指定する宛先ホストを変える必要があります。
手法としては以下のようなアルゴリズムが考えられます。
- 宛先クラスタに所属する全ホストを配列に格納
- 配列の長さを取得
- ループ内で指定する配列のIndex番号を格納する変数を定義し、0で初期化する
- ループ毎にインデックス番号をインクリメントする
- Move-VMコマンドで指定するHostをインデックス番号で指定してvMotionをする
- インデックスが配列長に達したら0にもどす
上記のようなやり方が一般的と思いますが、今回はさぼって以下の一行で代替しました。
$destination = Get-Cluster -Name MARVIN* -Server vxrailVC | Get-VMHost | Get-Random -Count 1
要するに宛先クラスタ内の全ホストからランダムに1ホストをReturnしてくれるコマンドです。
これをMove-VMコマンドレットの前に実行すればvMotion毎に宛先ホストをランダムに変更できます。
複数vNIC/複数PortGroupを持つVMであってもそれぞれ適切な宛先PortGroupを指定できるようにする
実はMove-VMで指定する-NetworkAdapter オプションと -PortGroup オプションはそれぞれ配列を指定できます。
それぞれ配列は対応するインデックス番号とペアとみなされて処理されます。
すなわち、-NetworkAdapter でしたした配列の1番目のvNICは、-PortGroupで指定した配列の1番目のPortGroupに移行されます
このあたりの詳細や、配列の数に差異があった場合の動作などは以下のブログをご参考にしてください。
https://blogs.vmware.com/PowerCLI/2017/01/spotlight-move-vm-cmdlet.html
Move-VMコマンドで指定する際には-NetworkAdapter の配列に合う形で -PortGroup の配列を作成してあげればいいことになります。
たとえば、以下のVMの-NetworkAdapter の配列 に合う配列はどのようなものになるでしょうか?(画像①)
※画像①
宛先側のClusterで、
LAB ポートグループ → MARVIN* ポートグループ
vCentere* ポートグループ → vCenter* ポートグループ
としたいすると以下のように作成できます。
$destinationPortGroups += Get-VDPortgroup -VDSwitch (Get-VDSwitch -Server vxrailVC) -Name MARVIN*
$destinationPortGroups += Get-VDPortgroup -VDSwitch (Get-VDSwitch -Server vxrailVC) -Name vCenter*
ここで配列に格納する順番は重要です。順番が間違っていると意図したポートグループではないほうのポートグループに移行されてしまい、場合によってはサービスが停止する可能性があります。
さぁ、これであとはここまでで紹介したコマンドを組み合わせて実際に移行をしてみるだけなのですが、ちょっと待ってください。
例えば以下のようなVMについてはどうなると思いますか?(画像②)
※画像②
ここでもう一度今回のMove-VMの条件をおさらいしましょう。
対象VMの条件は、
・test フォルダに所属している
・vNICを二つ持ちそれぞれ別のポートグループに所属している
・一つのvNICはLAB ポートグループに所属している
・もう一つのvNICはvCenter Server Network-a5643020-0c6e-471b-8baf-6aa1021583b5 に所属している
ポートグループの紐づけ条件は、
・LAB → MARVIN*
・vCentere* → vCenter*
でしたね。
例で提示した画像①のVMと画像②のVMは両方とも同じ条件を満たす必要があり、対象VMとして条件は満たしています。(つまり両方ともグルーピング条件に一致します。)
ポートグループの紐づけも一致する必要があるのですが、画像①のVMと画像②のVMではネットワークアダプタに対応するポートグループの順序が異なっており、このままではどちらかのVMにて正しくポートグループの移行がなされません。
Move-VMコマンド毎に-PortGroup の配列 の順序を変えれば解決できますが、それをしてしまうとそもそもPortGroupを基準としたグルーピングをした意味がなくなります。(結局同じPortGroupを使用しているVMであっても別のコマンドが必要なり一括処理ができなくなる)
同じポリシーで作成したVMにてvNICの順序が変わってしまうことは考えにくいですが、障害などが絡んで手動で再構成などをした場合、可能性はゼロではありません。これが基幹系のVMであったなら重大なサービス影響が出る可能性があります。
この問題をどのように解決したらいいでしょうか?
実はこの答えはすでに提示済みです。
グルーピングで紹介したforeachループの中に赤く強調した部分があったのは覚えていますでしょうか?
対象の部分だけ再掲します。
$networkAdapters = (Get-Networkadapter -VM $vm) | Sort-Object -Property NetworkName
$networkAdapters はMove-VMコマンドレットにて-NetworkAdapter の引数として指定する配列です。
この配列を作成する際に、NetworkNameでソートして配列エントリの順番を整えているのです。
実際に画像②のVMに対してこのソートを入れて配列を作成するとどうなるでしょうか?
実際に見てみましょう。(画像③)
※見やすさのため、一部コマンド出力が切れています。
※画像③
画像②も再掲します。
お判りでしょうか?画像②と画像③を比較するとvNICの順番が変わっており、画像③の状態であれば画像①のVMと同じコマンドでMove-VMコマンドを発行することが可能となります。
出来上がったコマンド例
PowerCLIやPowerShellに不慣れな方には、少々難しくわかりにくい部分があったかと思いますが、冒頭に上げた3つの課題はすべて解決されました。
最後に3つを組み合わせて出来上がったコマンドサンプルを紹介して終わりとさせていただきます。
# ソースとターゲットのVCに接続する
$cre = Get-Credential
Connect-VIServer -Server non-vxrailVC -Credential $cre
Connect-VIServer -Server vxrailVC -Credential $cre
# 宛先データストアを指定
$destinationDatastore = Get-Datastore -Server vxrailVC -Name MARVIN*
# 宛先ポートグループの配列を作成
$destinationPortGroups = @()
$destinationPortGroups += Get-VDPortgroup -VDSwitch (Get-VDSwitch -Server vxrailVC) -Name MARVIN*
$destinationPortGroups += Get-VDPortgroup -VDSwitch (Get-VDSwitch -Server vxrailVC) -Name vCenter*
# testフォルダに所属するVM一覧でループを回す
foreach ($vm in @((Get-Folder -Server non-vxrailVC -Name test | Get-VM))) {
#各VMのvNIC情報を取得し、条件に合うものをif文で抽出
$networkAdapters = (Get-Networkadapter -VM $vm) | Sort-Object -Property NetworkName
if ( (get-networkadapter -VM $vm | measure).count -eq 2 -And $networkAdapters.NetworkName.Contains("LAB") -And $networkAdapters.NetworkName.Contains("vCenter Server Network-a5643020-0c6e-471b-8baf-6aa1021583b5") ) {
#抽出したVMに対して、Move-VMコマンドレットで移行を実施する
$networkAdapters = Get-NetworkAdapter -VM $vm | Sort-Object -Property NetworkName
# 宛先クラスタのHost一覧からランダムに1ホストを指定
$destination = Get-Cluster -Name MARVIN* -Server vxrailVC | Get-VMHost | Get-Random -Count 1
$vm | Move-VM -Destination $destination -NetworkAdapter $networkAdapters -PortGroup $destinationPortGroups -Datastore $destinationDatastore -RunAsync
}
}
いかがでしたでしょうか?
今回紹介したコマンドに手を加えることで、VMをポートグループベースでグルーピングして、同じ移行条件にてホストを分散しつつの移行が可能になりました。
移行先と移行元でポートグループ名の一致させておき、それぞれのVMに合わせた形で宛先ポートグループの配列を作るようにスクリプトを組むこともできそうですが、よほど大規模かつ複雑で、多種多様なvNIC数とポートグループの組み合わせを持つ環境でもない限りは、この程度で十分なのではないでしょうか?
ご参考にしていただければ幸いです。