Вложенная виртуализация (Nested Virtualization) на Microsoft Hyper-V: различия между версиями
KOleg (обсуждение | вклад) |
KOleg (обсуждение | вклад) |
||
(не показана 1 промежуточная версия этого же участника) | |||
Строка 1: | Строка 1: | ||
− | + | __TOC__ | |
== Вложенная виртуализация (Nested Virtualization) на Microsoft Hyper-V впервые появилась в Windows 10. == | == Вложенная виртуализация (Nested Virtualization) на Microsoft Hyper-V впервые появилась в Windows 10. == | ||
Мы часто пишем о проблемах вложенной виртуализации (nested virtualization), которая представляет собой способ запустить виртуальные машины на гипервизоре, который сам установлен в виртуальной машине. На платформе VMware ESXi эта проблема давно решена, и там nested virtualization работает уже давно, мало того - для виртуального ESXi есть даже свои VMware Tools. | Мы часто пишем о проблемах вложенной виртуализации (nested virtualization), которая представляет собой способ запустить виртуальные машины на гипервизоре, который сам установлен в виртуальной машине. На платформе VMware ESXi эта проблема давно решена, и там nested virtualization работает уже давно, мало того - для виртуального ESXi есть даже свои VMware Tools. | ||
Строка 30: | Строка 30: | ||
[[Файл:windows-10-nested-hyper-v-5.png|400px]] | [[Файл:windows-10-nested-hyper-v-5.png|400px]] | ||
− | + | Надо отметить, что для вложенных виртуальных машин не поддерживаются следующие операции (как минимум): | |
*Dynamic Memory | *Dynamic Memory | ||
*Горячее изменение памяти работающей ВМ | *Горячее изменение памяти работающей ВМ |
Текущая версия на 14:20, 15 августа 2018
Вложенная виртуализация (Nested Virtualization) на Microsoft Hyper-V впервые появилась в Windows 10.
Мы часто пишем о проблемах вложенной виртуализации (nested virtualization), которая представляет собой способ запустить виртуальные машины на гипервизоре, который сам установлен в виртуальной машине. На платформе VMware ESXi эта проблема давно решена, и там nested virtualization работает уже давно, мало того - для виртуального ESXi есть даже свои VMware Tools.
Как мы недавно писали, решения для вложенной виртуализации на платформе Microsoft Hyper-V не было. При попытке запустить виртуальную машину на виртуальном хосте Hyper-V администраторы получали вот такую ошибку:
VM failed to start. Failed to start the virtual machine because one of the Hyper-V components is not running.
Все это происходило из-за того, что Microsoft не хотела предоставлять виртуальным машинам средства эмуляции техник аппаратной виртуализации Intel VT и AMD-V. Стандартная схема виртуализации Hyper-V выглядела так:
Virtualization Extensions передавались только гипервизору хостовой ОС, но не гостевой ОС виртуальной машины. А без этих расширений виртуальные машины в гостевой ОС запущены быть не могли.
В Windows 10 Build 10565 (этот превью-билд можно скачать по этой ссылке для x64 и по этой для x86) компания Microsoft, наконец-то, решила поменять ситуацию: теперь Virtualization Extensions передаются в гостевую ОС:
Соответственно, это позволит запустить вложенные виртуальные машины на хосте, который сам является виртуальной машиной с гостевой ОС Windows и включенной ролью Hyper-V.
На данный момент работает это только с Intel VT, но по идее к релизу Windows Server 2016 должно заработать и для AMD-V.
Сфера применения вложенных виртуальных машин не такая уж и узкая. Сейчас видится 2 основных направления:
- Виртуальные тестовые лаборатории, где развертываются виртуальные серверы Hyper-V и строятся модели работающих виртуальных инфраструктур в рамках одного физического компьютера.
- Использование контейнеризованных приложений (например, на движке Docker) в виртуальных машинах на виртуальных хостах Hyper-V. Более подробно о Windows Server Containers можно почитать вот тут. Немногим ранее мы писали об аналогичной архитектуре на базе VMware vSphere, анонсированной на VMware VMworld 2015.
Надо отметить, что для вложенных виртуальных машин не поддерживаются следующие операции (как минимум):
- Dynamic Memory
- Горячее изменение памяти работающей ВМ
- Снапшоты
- Live Migration
- Операции save/restore
Ну и вообще, вряд ли вложенная виртуализация вообще когда-нибудь будет полностью поддерживаться в производственной среде. Кстати, вложенная виртуализация на сторонних гипервизорах (например, VMware vSphere) также не поддерживается.
Для того, чтобы вложенная виртуализация заработала, нужно:
1. Использовать Windows 10 Build 10565. Windows Server 2016 Technical Preview 3 (TPv3) и Windows 10 GA - не подойдут, так как в них возможности Nested Virtualization нет.
2. Включить Mac Spoofing на сетевом адаптере виртуального хоста Hyper-V, так как виртуальный коммутатор хостового Hyper-V будет видеть несколько MAC-адресов с этого виртуального адаптера.
3. В Windows 10 нужно отключить фичу Virtualization Based Security (VBS), которая предотвращает трансляцию Virtualization Extensions в виртуальные машины.
4. Предусмотреть память под сам гостевой гипервизор и под все запущенные виртуальные машины. Память для гипервизора можно рассчитать так:
Теперь для того чтобы включить Nested Virtualization, выполните следующий сценарий PowerShell (в нем и VBS отключается, и Mac Spoofing включается):
Invoke-WebRequest https://raw.githubusercontent.com/Microsoft/Virtualization-Documentation/master/hyperv-tools/Nested/Enable-NestedVm.ps1 -OutFile ~/Enable-NestedVm.ps1
~/Enable-NestedVm.ps1 -VmName <VmName>
Далее создайте виртуальную машину на базе Windows 10 Build 10565, и включите в ней Mac Spoofing (если вы не сделали это в скрипте). Сделать это можно через настройки ВМ или следующей командой PowerShell:
Set-VMNetworkAdapter -VMName <VMName> -MacAddressSpoofing on
Ну а дальше просто запускайте виртуальную машину на виртуальном хосте Hyper-V:
Скрипт 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)";
} 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 "\tSaved 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 Address Spoofing isn't enabled (nested guests won't have network)." -ForegroundColor Yellow
Write-Host "Would you like to enable MAC address spoofing? (Y/N)" -NoNewline
$input = Read-Host
if($input -eq 'Y') {
Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing on
}
else {
Write-Host "Not enabling Mac address spoofing."
}
}
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') {
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'