ついに実現したNested Hyper-V を体感してみる

Hyper-Vユーザーが待ち望んでいた機能がついに実現!Nested Hyper-Vとは一体どんなものなのか、何ができるのかを解説

2015年11月にリリースされたWindows Server 2016 Technical Preview 4(TP4)では、以前から予告されていたNested Hyper-Vを実際に利用できるようになりました。まだプレビュー版ということもあり、いくつか制限があるものの、多くのHyper-Vユーザーが待ち望んでいた機能がついに実現しました。Nested Hyper-Vとは一体どんなものなのか、何ができるのかを実際にNested Hyper-Vの構築方法を紹介しつつ、解説していきます。

Nested Hyper-V とは?

まず、Nested Hyper-Vとは一体何なのかを簡単に言うと、Hyper-V上の仮想マシンの中でさらにHyper-Vの機能を有効にすることができる、というものです。日本語に言い換えれば「入れ子」状態ということになります。

Windows Server 2012 R2までは、Hyper-V上の仮想マシン内ではHyper-Vの機能自体をインストール・有効にすることができませんでした。

図1 2012R2の仮想マシンでHyper-Vを追加しようとするとエラー

Hyper-Vは仮想マシンに対して、物理サーバーが提供している仮想化機能を使って各種ハードウェアを仮想化しているので、仮想マシン自体に物理サーバーと同様の仮想化機能が搭載されておらず、Hyper-V上でHyper-Vを有効にすることができませんでした。

TP4で提供されたHyper-Vでは、仮想マシン自体が物理サーバーと同様の仮想化機能を提供することができるようになった(仮想マシン自体が物理サーバーの仮想化技術を透過して提供できるようになった)ため、Nested Hyper-Vを実現することができるようになりました。現時点では、3階層までHyper-VをNestedできることが検証環境で確認できましたが、これ以上のNestedもハードウェアのリソースが許す限りは可能なようです。

図2 Nested Virtualizationより

Nestedの必要性

これまでもHyper-V上でHyper-Vを利用したいという話を度々耳にすることがありました。筆者自身もこのNestedは是非実現してほしかった機能の一つなのです。

では、なぜNestedが必要とされていたのでしょう。

1つ目は、エンジニアの現場での検証環境として、Nestedは待望視されていました。Hyper-Vを仮想化プラットフォームとすると、Hyper-V自体の様々な機能を利用することができます。Live Migrationや、Hyper-Vクラスタ、Microsoft Azureのサービスを利用したクラウド連携などなど、とても優れた機能が提供されています。
これらを実際のシステムで利用する場合には、やはり徹底した検証が必要となりますが、Hyper-Vはこれまでは物理サーバーにWindows Serverをインストールして利用するに限られていました。検証環境の構築において、物理サーバーを1台から数台占有してしまうことや、インストールの手間、再三の作り直しの手間を考えるとなかなか大変な作業となっていました。仮想マシンの一つとしてHyper-Vの環境が構築できるとなると、各段の効率アップと時間短縮を実現することができます。

2つ目は、サービスの提供環境としてHyper-Vのシステム自体が仮想化されていることは、サービス運用上とても効率がよいということです。トラブルに対してのバックアップ、リストア作業が仮想マシンと同様に簡略化されます。ハードウェア入れ替えといったメンテナンスに対しても、仮想化されていることのメリットは言うに及ばずといったところです。
さらには、これまでHyper-Vを利用したいといったユーザーに対してサービサーが提供するのは、サーバー1台丸ごとといった大変高価な環境でしたが、ユーザーの要望に応じてリソースを振り分けられる低価格のHyper-Vそのものを提供できるようになりました。社内におけるプライベートクラウド構築とった場面においても、高価なハードウェアを共有した上で、複数のプライベートクラウドを構築、提供することができるようになります。

3つめとしては、これから登場するWindows Server 2016で提供予定のHyper-Vコンテナを実現するために、Nested Hyper-Vは必要とされています。前々回の記事で紹介したWindowsコンテナですが、そのうちの1つ、Hyper-Vコンテナはよりセキュアなコンテナ実行環境を実現することができる技術です。通常のコンテナがコンテナホストを一部透過的に参照して実行しているのとは異なり、Hyper-Vコンテナは完全にコンテナホストや他のコンテナから隔離された状態で稼働する必要があります。
さらに、コンテナのメリットを最大限に生かすために、仮想マシンより軽く、速くする必要があります。そのためには、コンテナ技術を実現しつつ、これまでのHyper-V上の仮想マシンと同じレベルまでコンテナを隔離するための技術としてNested Hyper-Vの実現は重要な技術となっています。

図3 Hyper-Vコンテナ

Nested Hyper-Vの構築

まずはNested Hyper-Vを実現するための前提条件を確認してみましょう。(TP4現在)

・4GB以上の物理メモリ
・ホスト、仮想マシンともにWindows Server 2016 Technical Preview 4
・Intel VT-x が有効となっているハードウェア(IntelのCPUでHyper-Vが利用できるもの、AMD-Vは現時点では不可)


それでは順を追って構築していきます。

・まずは、ホストとなる物理マシンにTP4をインストールします。TP4からは日本語版も利用可能となっていますので、今回は日本語版のGUI付きをインストールします。

・物理ホストサーバーにTP4のインストールが完了したら、Hyper-Vの機能を有効にします。

・Hyper-V上に通常の仮想マシンを作成して、こちらも同様にTP4をインストールします。仮想マシンはまだHyper-Vの機能を有効にしません。

図4 ホスト、仮想マシンともにTP4をインストールする

・Nested Hyper-Vを有効にするためのスクリプトをダウンロードして、Hyper-Vホスト上で実行します。

Invoke-WebRequest https://raw.githubusercontent.com/Microsoft/Virtualization-Documentation/master/hyperv-tools/Nested/Enable-NestedVm.ps1 -OutFile C:\Enable-NestedVm.ps1

C:\Enable-NestedVm.ps1 -VmName "TestVM"

This script will set the following for TestVM in order to enable nesting:
Vm State: Running
  TestVM will be turned off
  Virtualization extensions will be enabled
  Optionally enable mac address spoofing
Input Y to accept or N to cancel:Y
警告: 入れ子構造の仮想化は、サポートされていないプレビュー機能です。ゲスト仮想マシンで実行されている Hyper-V ハイパーバイザー以外のハイパーバイザーでは、エラーが発生する可能性があります。さらに、Hyper-Vの一部の機能には、動的メモリ、チェックポイント、保存/復元などの入れ子構造の仮想化との互換性がありません。
Mac Adderess Spoofing isn't enabled, nested guests won't have network!

Would you like to enable? (Y/N)Y

次に仮想マシンにログインして、Hyper-Vの機能を有効にします。

図5 仮想マシンでHyper-Vの機能を有効

仮想マシン内のHyper-V上でさらに仮想マシンを作成して起動してみました。Nested Hyper-Vの完成です。

図6 入れ子状態のHyper-V

TP4現在のNested Hyper-Vの制限事項

待望のNested Hyper-Vですが、TP4はあくまでも早期プレビュー版ということで、いくつか制限事項があります。

・仮想マシンのダイナミックメモリの利用不可
・動的メモリ量の変更不可
・チェックポイントの適用不可
・Live Migrationの利用不可
・保存・起動の利用不可

おおよそメモリ関係のいくつかの機能が現時点では利用できないようです。

これらの制限は、最初の物理Hyper-Vホスト上に作成された仮想マシンに限定されたもので、NestedされたHyper-V上の仮想マシンはこの制限事項には当てはまりません。
Nestedを行う場合、メモリ容量については不足しないように十分に割り当てようと考えると思いますが、注意すべきはCPUのコア数です。ホストとなるHyper-Vに十分な仮想コアを割り当てないと、Nested上で仮想マシンを起動した場合エラーとなる場合があります。

図7 仮想マシンの起動エラー

Nested Hyper-Vのパフォーマンス

さて、仮想化の多重化で使いやすくなりそうなHyper-Vですが、Nestedすることでパフォーマンスへの影響はどうなるのかが気になるところです。

検証環境では、物理サーバーのHyper-V上に、レベル2としてNestedした仮想マシンを作成しました。さらに、レベル3、レベル4として、NestedしたHyper-V上にさらに仮想マシンを作成しています。同じ仮想マシンでも、仮想化が多重化された場合、ボトルネックやオーバーヘッドが発生する可能性があります。実際に操作した体感としては、階層が深くなるほど仮想マシンのGUI操作が若干もたつくような気がします。

実際にレベル2、レベル3とレベル4の仮想マシンを同様のスペック状態にしてベンチマークを取った結果です。

図8 Lv.2
図9 Lv.3
図10 Lv.4

やはり数値的にみても、階層が深い方が全体的なパフォーマンスが若干劣っているようです。
ただし、極端に性能が劣化するというわけではなく、これだけのパフォーマンスを実現しつつNestedが現実化していることのほうが、注目すべき点だと思われます。

Enable-NestedVm.ps1 の解析

最後に、Nested Hyper-Vの設定を行うためのスクリプトの中身を簡単に見てみましょう。

Nested化の手順としては、仮想マシンを停止状態にしたうえで、制限項目である「DynamicMemoryEnabled」や「MacAddressSpoofing」を無効としています。また、メモリサイズを4GB以上としています。
ポイントとなるのは「ExposeVirtualizationExtensions」をTrueとしている部分です。

このプロパティはTP4から新しく追加されたもので、Nestedを有効にする、しないのフラグとなっています。「Get-VMProcessor」コマンドで仮想マシンのプロセッサー情報を確認してみると、Nestedの設定を行った場合は「ExposeVirtualizationExtensions」のプロパティはTrueとなっていることが分かります。

Get-VMProcessor TestVM | Select *

VMCheckpointId
: 00000000-0000-0000-0000-000000000000
VMCheckpointName
:
ResourcePoolName
: Primordial
Count
: 4
CompatibilityForMigrationEnabled
: False
CompatibilityForOlderOperatingSystemsEnabled
: False
HwThreadCountPerCore
: 1
ExposeVirtualizationExtensions
: True
Maximum
: 100
Reserve
: 0
RelativeWeight
: 100
MaximumCountPerNumaNode
: 8
MaximumCountPerNumaSocket
: 1
EnableHostResourceProtection
: False
OperationalStatus
: {Ok, HostResourceProtectionDisabled}
StatusDescription
: {OK, ホスト リソース保護は無効です。}
Name
: プロセッサ
Id
: Microsoft:862A6E40-A3E5-4E22-890A-AFC7AF788A9F\b637f346-6a0e-4dec-af52-bd70cb80a21d\0
VMId
: 862a6e40-a3e5-4e22-890a-afc7af788a9f
VMName
: TestVM
VMSnapshotId
: 00000000-0000-0000-0000-000000000000
VMSnapshotName
:
CimSession
: CimSession: .
ComputerName
: WIN-O1JFL8DSG92
IsDeleted
: False

Enable-NestedVm.ps1

param([string]$vmName)
#
# Enable-NestedVm.ps1
#
# Checks VM for nesting comatability and configures if not properly setup.
#
# Author: Drew Cross

if([string]::IsNullOrEmpty($vmName)) {
  Write-Host "No VM name passed"
  Exit;
}

# Constants
$4GB = 4294967296

#
# Need to run elevated. Do that here.
#

# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);

# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;

# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole)) {
  # We are running as an administrator, so change the title and background colour to indicate this
  $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
#$Host.UI.RawUI.BackgroundColor = "DarkBlue";
  Clear-Host;
  } else {
  # We are not running as an administrator, so relaunch as administrator

  # Create a new process object that starts PowerShell
  $newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";

  # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
  $newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"

  # Indicate that the process should be elevated
  $newProcess.Verb = "runas";

  # Start the new process
  [System.Diagnostics.Process]::Start($newProcess) | Out-Null;

  # Exit from the current, unelevated, process
  Exit;
  }

#
# Get Vm Information
#

$vm = Get-VM -Name $vmName

$vmInfo = New-Object PSObject

# VM info
Add-Member -InputObject $vmInfo NoteProperty -Name "ExposeVirtualizationExtensions" -Value $false
Add-Member -InputObject $vmInfo NoteProperty -Name "DynamicMemoryEnabled" -Value $vm.DynamicMemoryEnabled
Add-Member -InputObject $vmInfo NoteProperty -Name "SnapshotEnabled" -Value $false
Add-Member -InputObject $vmInfo NoteProperty -Name "State" -Value $vm.State
Add-Member -InputObject $vmInfo NoteProperty -Name "MacAddressSpoofing" -Value ((Get-VmNetworkAdapter -VmName $vmName).MacAddressSpoofing)
Add-Member -InputObject $vmInfo NoteProperty -Name "MemorySize" -Value (Get-VMMemory -VmName $vmName).Startup


# is nested enabled on this VM?
$vmInfo.ExposeVirtualizationExtensions = (Get-VMProcessor -VM $vm).ExposeVirtualizationExtensions

Write-Host "This script will set the following for $vmName in order to enable nesting:"

$prompt = $false;

# Output text for proposed actions
if ($vmInfo.State -eq 'Saved') {
  Write-Host "\tSaveed state will be removed"
  $prompt = $true
}
if ($vmInfo.State -ne 'Off' -or $vmInfo.State -eq 'Saved') {
  Write-Host "Vm State:" $vmInfo.State
  Write-Host " $vmName will be turned off"
  $prompt = $true
}
if ($vmInfo.ExposeVirtualizationExtensions -eq $false) {
  Write-Host " Virtualization extensions will be enabled"
  $prompt = $true
}
if ($vmInfo.DynamicMemoryEnabled -eq $true) {
  Write-Host " Dynamic memory will be disabled"
  $prompt = $true
}
if($vmInfo.MacAddressSpoofing -eq 'Off'){
  Write-Host " Optionally enable mac address spoofing"
  $prompt = $true
}
if($vmInfo.MemorySize -lt $4GB) {
  Write-Host " Optionally set vm memory to 4GB"
  $prompt = $true
}

if(-not $prompt) {
  Write-Host " None, vm is already setup for nesting"
  Exit;
}

Write-Host "Input Y to accept or N to cancel:" -NoNewline

$char = Read-Host

while(-not ($char.StartsWith('Y') -or $char.StartsWith('N'))) {
  Write-Host "Invalid Input, Y or N"
  $char = Read-Host
}


if($char.StartsWith('Y')) {
  if ($vmInfo.State -eq 'Saved') {
    Remove-VMSavedState -VMName $vmName
  }
  if ($vmInfo.State -ne 'Off' -or $vmInfo.State -eq 'Saved') {
    Stop-VM -VMName $vmName
  }
  if ($vmInfo.ExposeVirtualizationExtensions -eq $false) {
    Set-VMProcessor -VMName $vmName -ExposeVirtualizationExtensions $true
  }
  if ($vmInfo.DynamicMemoryEnabled -eq $true) {
    Set-VMMemory -VMName $vmName -DynamicMemoryEnabled $false
}

  # Optionally turn on mac spoofing
  if($vmInfo.MacAddressSpoofing -eq 'Off') {
    Write-Host "Mac Adderess Spoofing isn't enabled, nested guests won't have network!" -ForegroundColor Yellow
    Write-Host "Would you like to enable? (Y/N)" -NoNewline
    $input = Read-Host

    if($input -eq 'y' -or 'Y') {
      Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing on
    }
    else {
      Write-Host "Not setting Mac Address Spoofing feature (can be enabled via UI)."
    }

  }

  if($vmInfo.MemorySize -lt $4GB) {
    Write-Host "Vm memory is set less than 4GB, without 4GB or more, you may not be able to start VMs!" -ForegroundColor Yellow
    Write-Host "Would you like to set Vm memory to 4GB? (Y/N)" -NoNewline
    $input = Read-Host

    if($input -eq 'y' -or 'Y') {
      Set-VMMemory -VMName $vmName -StartupBytes $4GB
    }
    else {
      Write-Host "Not setting Vm Memory to 4GB"
    }
  }
  Exit;
}

if($char.StartsWith('N')) {
  Write-Host "Exiting..."
  Exit;
}

Write-Host 'Invalid input'


以上、待望のNested Hyper-Vを実際に体感してみました。プレビュー版ということでしたが、思っていたよりもきちんと動くものとなっており、Nestedした時のパフォーマンスの劣化もそれほど問題になるほどのものではありませんでした。

正式リリースまではまだ時間がかかるものの、Hyper-Vコンテナとともに、Nested Hype-Vも十分に期待できるものだと感じています。

是非お試しください。

著書の紹介欄

Hyper-Vで本格的なサーバー仮想環境を構築。仮想環境を設定・操作できる!

できるPRO Windows Server 2016 Hyper-V

◇Hyper-Vのさまざまな機能がわかる ◇インストールからの操作手順を解説 ◇チェックポイントやレプリカも活用できる Windows Server 2016 Hyper-Vは、仮想化ソフトウェア基盤を提供する機能であり、クラウドの実現に不可欠のものです。 本書では、仮想化の基礎知識から、Hyper-Vでの仮想マシンや仮想スイッチの設定・操作、プライベートクラウドの構築、Azureとの連携などを解説します。

初めてのWindows Azure Pack本が発売

Windows Azure Pack プライベートクラウド構築ガイド

本書は、Windows Azure PackとHyper-Vを利用し、企業内IaaS(仮想マシン提供サービス)を構成するための、IT管理者に向けた手引書です。試用したサーバーは、最小限度の物理サーバーと仮想マシンで構成しています。Windows Azure Packに必要なコンポーネントのダウンロード、実際にプライベートクラウド構築する過程を、手順を追って解説しています。これからプライベートクラウドの構築を検討するうえで、作業負担の軽減に役立つ一冊です。

ブログの著者欄

樋口 勝一

GMOインターネットグループ株式会社

1999年6月GMOインターネットグループ株式会社に入社。Windows Serverをプラットフォームとしたサービス開発から運用・保守まで幅広く担当。講演登壇や出版、ネット記事連載などでマイクロソフト社と強い信頼関係を構築。「マイクロソフトMVPアワード」を15度受賞し、インターネットソリューションのスペシャリストとして活躍。

採用情報

関連記事

KEYWORD

採用情報

SNS FOLLOW

GMOインターネットグループのSNSをフォローして最新情報をチェック