2020/09/27

Windows Server 2019でHyper-Vをvhdx形式で自動バックアップするには

もはや不動産とも金融とも関係ないエントリーですが、危機対策としてバックアップは大事です。
当社では、日々の業務から金融、会計などいろいろな業務をVM上で動かしていて、機能ごとにコンテナ化しているため、これをバックアップしたいというわけです。

いくつかあるHyper-Vのバックアップ方法

Windows Backup Service(WBS)を使う

「WindowsImageBackup」というフォルダが作成されてW2019サーバーがまるごとバックアップされる。バックアップ世代ごとに差分管理される。
というメリットはありますが、バックアップ先のディスクが特殊なロックをされて、
WBadmin delete backup -keepversions:0 -backuptarget:f: (fドライブのバックアップをすべて消す)
など複雑なことをしないとパーティション削除すらできないなど面倒。
かつ、緊急時に、本当に復元できるのか、かなり怪しい(WindowsImageは、なんだかんだエラーで復元できないことが多い)ということから、これは使いたくない。
緊急時はシンプルな生データが最も信頼できる。

Hyper-V ライブマイグレーションを使う

同じようなスペックのWindows Server 2019が2つあれば、本番サーバーからバックアップサーバーにVMが起動したままの状態でミラーリングコピーのようなことができる。サーバー機器が余っていないし、そこまで大がかりな仕掛けは不要で、一日一回バックアップが取れれば良い。

vhdxファイルをコピーする

VMが電源offの状態でコピーするならば他の場所で再生できると思うが、毎度、それをやって再起動し直しは面倒過ぎて実用的でない。起動中にファイルコピーしたら正常にデータ更新が反映されないで調子悪くなりそう(試したことはないですが、やめたほうがよい)

エクスポート機能を使う(→これを応用)

vhdxファイルのコピーとほぼ同じことをWindowsの正規手順で行う機能。つまり、VMが動いているときでも正常にvhdxファイルを抜き出せる。かつ、エクスポート中はVMの動作が止まらない。シンプル&無問題。これでいいでしょう。所要時間はインストールしたてのWindows10で3-4分?

エクスポート機能の問題点と解決策

稼働しているVMがたくさんあると、個別に毎回、エクスポートボタンを押さないといけないので面倒というか、数十件あると現実的でない。
これを自動化できないか。


Hyper-V Backup Utility というのを使えばそれができます。PowerShellで動く簡単なソフトです。PS1(スクリプト)でありオープンソースなので、第三国に勝手にデータが送信される等の心配もなし。

Hyper-V Backup Utilityの使い方


タイトルが昭和っぽいが動作は良好

ここからダウンロードする
https://github.com/Digressive/HyperV-Backup-Utility

マニュアルこちら
https://github.com/Digressive/HyperV-Backup-Utility/blob/master/README.md

PowerShell上でPS1が動くようにする

初期状態ではPowerShell上ではPS1の実行はセキュリティで禁止されているので、Set-ExecutionPolicy Unrestricted として無制限にPS1が実行できるようにする。

セキュリティにうるさい人はもう少し細かい設定もできるようです。下記参照。
https://qiita.com/tomoko523/items/df8e384d32a377381ef9

7-zipをインストールする

64bit版をデフォルト設定でインストールすれば良い

先に作業用フォルダ(c:\tmp)をきれいにしておく

けっこう単純なスクリプトなので、既存でゴミファイル(前回のスクリプト実行が失敗したときにできた中途半端なデータ)などが残っていると、ファイルが既に存在しているとか、上書きエラーなどが出そうなので、一応、作業フォルダのファイルをすべて消してから起動
Remove-Item c:\tmp\* -Recurse
-Recurseを付けるとサブフォルダもすべて消す。再帰的という意味。

PS1の置いてあるフォルダに移動

cd \hyperv-backup
など

Hyper-V Backup Utilityを実行

結論的にはこんな感じのコマンドを投入すれば良い
.\hyper-v-back.ps1 -compress -Sz -Szthreads mmt8 -Wd c:\tmp -backupto f: -list C:\hyperv-backup\list.txt

Powershell上でPS1を起動するには.\から記述する必要がある様子
-compress データを7zipで圧縮する。vhdxは圧縮すると半分くらいになることも
-Sz 7zipを使って圧縮。7zip
2020-09-27 12:20:02 [INFO] Compressing _vm名 backup using 7-Zip compression と出たら7zipが動いている
Compressing $Vm backup using Windows compression と出たら7zipがうまく動作していない
-compress を忘れるとだめ -Sz だけ指定しても圧縮されません
-Szthreads mmt8 CPUの8スレッドを使って7zipを動かす。最大8までしか設定できないらしいです
-Wd c:\tmp 圧縮などを実施する作業フォルダ
-backupto f: fドライブのルートにバックアップする
-list C:\hyperv-backup\list.txt バックアップするVM名の一覧をテキストファイルで作る。このパラメーターを省略するとすべてのVMがバックアップされる

.\hyper-v-back.ps1 -backupto f:
単純にすべてのvmをf:ルートにvhdxをエクスポートするだけならこれで良い。作業用フォルダは指定しなくても動く(f:に直接エクスポートする動作になるはず)NASには直接エクスポートせず作業フォルダからコピーするか、ローカルの作業フォルダにvhdxを作るところまでHyper-V Backup UtilityにやらせてNASへのコピーはrobocopyなど違うコマンドを使った方が良いかも

Hyper-V Backup Utilityの問題点と解決策

ディスク容量を食う

動作として、
・VMファイル(vhdxなど)を作業フォルダにエクスポート(コピー)する
・複数VMを指定している場合は先にまとめてエクスポートする
・すべてエクスポートが終わってから、作業フォルダ上で7zipで圧縮する
ということをするので、7zip圧縮をするならば作業フォルダにはvhdx容量の2倍くらいの容量が必要で、使い方によっては容量が足りない。

list.txtを小分けにして使って、作っては消しで、複数回Hyper-V Backup Utilityを実行させる必要あり。
もしくは、バックアップ先に2倍の容量のディスクを用意して、すべてのVMをまとめてコピー(圧縮しない)、このスクリプトは使わず、自分で7zipで圧縮するようなバッチファイルにするのが良いと思います。Hyper-V Backup Utilityでコピー>7zipで圧縮>生データは消して7zだけ残す
法人ならば、緊急の際に7zが解凍できないリスクを考えると、圧縮しないで大容量のハードディスクを買うべきでしょう。

循環記録は標準対応ではない

数世代のバックアップを保管して、古いものから消していく。そのような動作をするには追加でスクリプトを自作する必要あり。
1.net useでNASをドライブとしてマウント(WS2019からは標準ではバッファローのNASは開けない。WS2019側でSMB1.0を有効化する必要あり)
2.NASのデータをすべて消す
3.ローカルHDDからNASにrobocopy
4.ローカルHDDのデータをすべて消す
5.その後にHyper-V Backup Utilityを実行ですべてのVMをローカルHDDにエクスポート
などすれば良い

前後処理とともにスクスケジューラに組み込む

前後処理の具体的なコマンド

c:
cd \hyperv-backup
net use n: \\192.168.xxx.xxx\BuffaloNAS /user:admin pwpwパスワード文字列

net config server /autodisconnect:-1
→ネットワークドライブがアイドル時に自動で切断されないようにする

Remove-Item n:\hyper-v-bak\* -Recurse

New-Item f:\vm -ItemType Directory
New-Item n:\hyper-v-bak -ItemType Directory
→robocopyが終わるとvmフォルダごと削除されてしまうので再度作成。ディレクトリと同名のファイルが存在するとディレクトリ作成に失敗するので注意

robocopy f:\vm n:\vm_bak /s /e /mov /log+:c:\hyperv-backup\robocopylog.txt /copy:DT /fft /tee
→f:\vmのすべてをn:\vm_bakにコピーする(f:などドライブ名だけを指定するとゴミ箱などシステムファイルもコピーされてしまうのでやめたほうがよい)
/S :: サブディレクトリをコピーしますが、空のディレクトリはコピーしません。
/E :: 空のディレクトリを含むサブディレクトリをコピーします。
/MOVE :: ファイルとディレクトリを移動します (コピー後にコピー元から削除)。→コピーが終わると1ファイルごとに移動している様子
/LOG+:ファイル :: ログ ファイルに状態を出力します (既存のログ ファイルに追加します)。
/COPY:コピーフラグ :: ファイルにコピーする情報 (既定値は /COPY:DAT)。→DTに変更しないとコピーできない
/FFT :: FAT ファイル時間 (2 秒の粒度) を仮定します。 →コピー元と先で時刻の一致を検証するときに2秒誤差までは同一とみなす(NASなど別デバイスにコピーする時のため)
/TEE :: コンソール ウィンドウとログ ファイルに出力します。


このロボコピーという名前がRPAっぽくてよろしいため採用。本来はrobust copyという意味らしいです。

.\hyper-v-back.ps1 -backupto f:\vm
→PS1ファイルの実行は.\からはじまる

タスクスケジューラに組み込む

容量が大きいので毎週1回などで実行するのがよいでしょう