Привет, Хабр!
Периодически я слышу от практикующих инженеров странное: VMDK, VHD и VHDX – абсолютно разные форматы виртуальных дисков, чуть ли не закрытые, а конвертировать из одного в другое – долго и больно. Сегодня наглядно покажу, что это не так, разберу, как эти форматы соотносятся друг с другом и как делать быструю конвертацию при миграции с Hyper-V на VMware и обратно.
Немного теории. C точки зрения свойств, виртуальные диски делятся на два типа:
- тонкие (thin disk, dynamic disk) и
- толстые (thick disk, fixed disk). Все остальное — разностные, thick provisioned lazy- zeroed – лишь вариации на тему.
Подробно на этом останавливаться не буду. Скажу лишь, что дальше речь пойдет о толстых дисках.
Форматы дисков
RAW – «сырой» образ любого диска. Это обычный контейнер, который не содержит никаких специфических заголовков и футеров и представляет образ диска «как есть». Если мы откроем такой образ HEX-редактором, то сразу увидим заголовки GPT/MBR и/или файловой системы. Точно такой же образ получается через команду dd в Linux. RAW в этом плане абсолютно честен с нами.
Начало файла RAW.
Конец файла RAW.
VMDK. VMware ESXi – обыкновенный RAW, где геометрия диска описывается в обычном текстовом файле-описателе (дескрипторе). Именно его имя мы видим в vSphere Console, когда подключаем виртуальный диск к виртуальной машине или просматриваем содержимое каталога на Datastore. VMware ESXi ничего не делает с образом. Совсем. Диск покоится себе и расширяется по мере необходимости. В лучших традициях VMware формат описателя очень простой:
# Disk DescriptorFile
version=1
encoding="UTF-8"
CID=fffffffe
parentCID=ffffffff
isNativeSnapshot="no"
createType="vmfs"
# Extent description
RW 15122560 VMFS "disk-example-flat.vmdk"
# The Disk Data Base
#DDB
ddb.adapterType = "lsilogic"
ddb.geometry.cylinders = "941"
ddb.geometry.heads = "255"
ddb.geometry.sectors = "63"
ddb.longContentID = "4f5dc83d0a5270bee54e2d85fffffffe"
ddb.uuid = "60 00 C2 93 b4 38 ed dd-a3 85 88 48 68 40 2f c0"
ddb.virtualHWVersion = "13"
И он не только простой, но и функциональный: достаточно сделать пометки в файле-описателе, чтобы расширить виртуальный диск до каких угодно поддерживаемых значений. Это позволяет заполнить диски нулями или пометить его как тонкий, без необходимости держать информацию о геометрии в заголовках диска.
Ниже представлены некоторые стандартные значения всех разделов дескриптора:
Раздел |
Параметр |
Описание |
Значение |
Header (# Disk DescriptorFile) |
version |
Задает номер версии дескриптора. Обычно не меняется. |
1 (по умолчанию) |
CID |
Content ID. Случайный 32-битный идентификатор диска, участвующий в построении дерева снапшотов. Является ParentCID для дочерних дельта-дисков. |
Случайное 32-битное значение, генерируемое на момент создания. |
|
parentCID |
CID родительского диска. Если родительского диска нет, то выставляется флаг CID_NOPARENT (ffffffff). |
Ffffffff (CID_NOPARENT) CID родительского диска. |
|
createType |
Указатель на тип диска, описываемого в дескрипторе (это вполне может быть и физический диск, и разностные диски, и даже массив дисков VMDK). Для ESXi набор свойств ограничен. |
Для ESXi – vmfs (в случае виртуального диска) или vmfsRawDeviceMap и vmfsPassthroughRawDeviceMap (в случае RDM). |
|
isNativeSnapshot |
Помечает, какими средствами будет делаться снапшот: VMkernel или средствами СХД (VAAI). |
no (VMkernel), yes (VAAI) |
|
Extents (# Extent description) |
|
Раздел содержит путь к диску, тип доступа и размер. В формате: <тип доступа> <размер> <тип экстента> <путь к файлу VMDK или к устройству> <смещение>. |
|
Access |
Тип доступа к диску. |
RW (чтение/запись) RO (только чтение) NOACCESS (доступ запрещен). |
|
Size |
Размер диска. |
Указывается количество логических секторов виртуального диска. Вычисляется по формуле: <Размер в байтах>/<размер логического сектора> Подробнее о расчетах геометрии диска здесь. |
|
Type of extent |
Указатель на режим работы диска. |
Может принимать значение FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW. |
|
Filename |
Путь к файлу VMDK. |
|
|
Offset |
Используется, если необходимо указать смещение начала данных гостевой ОС. Для виртуальных дисков, как правило, равно 0 (или не указывается). Для RDM может быть ненулевым. |
Смещение в байтах относительно начала диска до начала блока данных. |
|
Disk Database (# The Disk Data Base) |
|
Описывает геометрию виртуального диска. |
|
ddb.adapterType |
Тип виртуального SCSI-адаптера ВМ. |
Поддерживаются только 3 типа: ide, buslogic, lsilogic. Причем адаптер VMware Paravirtual всегда помечается как lsilogic. |
|
ddb.geometry.cylinders ddb.geometry.heads = «255» ddb.geometry.sectors = «63» |
Количество цилиндров, головок и секторов для описания геометрии виртуального диска. |
Подробно о расчетах геометрии диска здесь. |
|
ddb.thinProvisioned |
Флаг тонкого диска. |
1 – диск тонкий, 0 или отсутствует – толстый диск |
|
ddb.uuid |
Идентификатор дескриптора |
|
|
ddb.virtualHWVersion |
Версия Virtual Hardware |
|
Описание всех значений можно посмотреть в спецификации формата: VMware Virtual Disk Format 1.1
VHD. Толстый VHD – тот же самый RAW, но с 512-байтным футером, где описывается геометрия диска. Какого-то отдельного файла-описателя у виртуальной машины Microsoft Hyper-V нет. Описание геометрии диска занимает 4 байта. Собственно, отсюда ограничение на размер диска в 2 Тб.
Футер. Последние 512 байт диска.
Самое интересное, что если создать файл-описатель и подсунуть в ESXi VHD-диск с футером, то гипервизор VMware проигнорирует этот футер и примет VHD как родной.
При Storage vMotion с конвертацией диска в тонкий он просто отрежет этот футер, и на выходе мы получим тот же RAW без нулей в конце. А при конвертации в толстый диск – честный RAW. Это я и собираюсь продемонстрировать чуть позже.
VHDX. Вся информация о геометрии диска хранится в первых 4096 Кбайтах виртуального диска – в области заголовка.
Общая схема толстого диска VHDX.
Что представляет из себя эта область? В ней содержатся две копии заголовков со своими логами, BAT и область метаданных общие.
Логическая структура заголовка диска.
В единицу времени только одна копия заголовка активна. Это обеспечивает определенный уровень отказоустойчивости заголовка в случае незапланированных прерываний операций чтения/записи. После каждой операции I/O копия реплицируется, и происходит переключение на нее.
Макет области заголовка.
Для конвертации VHDX в RAW нам всего-то нужно отрезать первые 4096 KB.
Начало данных на 5 МБ.
Внимательный читатель, конечно же, скажет: ок, Женька, а слабо RAW конвертнуть в VHDX? На что я отвечу: зависит от файловой системы и от того, насколько она позволяет записывать данные в начало файла. Вручную на файловой системе NTFS это можно сделать, сместив в MFT начало файла на 4 Мб вперед и дописав в это место заголовок.
По этому же принципу работает утилита vhdxtool.exe. Однако при этом преобразовании мы не получим красивую картинку в виде 4 Мбайт заголовка и RAW. Диск будет виден и даже будет корректно работать как VHDX, но будет и много «мусора» из нулей, появившихся из-за манипуляций со смещениями (offsets). Диск будет не оптимизирован. ВМ с таким диском рекомендуется смигрировать на другой том или оптимизировать через командлеты Convert-VHD или Optimize-VHD. Если этого не сделать, диск будет занимать больше места, чем должен, и, возможно, медленнее работать.
Однако в сценариях миграции с VMware на Hyper-V эта утилита незаменима, так как позволяет провести преобразование на месте, без необходимости побайтового считывания исходного диска и создания рядом копии. Все шероховатости будут сглажены при первом же Storage Live Migration.
Вывод: толстые диски форматов VMDK, VHD, VHDX на деле мало чем отличаются друг от друга. В их основе RAW c различными добавками. Тем же HEX-редактором или функциями ОС для работы с файловой системой мы можем за пару секунд превратить 10 Тб VMDK или VHDХ в диск целевого гипервизора.
Давайте на практике посмотрим, как VMware Exsi справится с VHD.
- В качестве примера я создал образ Windows Server с помощью Convert-WindowsImage с инъекцией драйверов VMware и параметрами:
- OS Version: Windows Server 2019 Standard,
- Disk Type: Fixed,
- Disk Layout: GPT,
- Disk Size: 30GB.
Обратите внимание на параметры FileSize (реальный размер файла) и Size (размер диска с точки зрения ВМ). Разница между значениями ровно 512 байт – размер футера VHD. - Переименуем диск в Win2019-test2-flat.vmdk для загрузки его на ESXi Datastore.
- Далее я создаю в VMware ESXi пустую ВМ с диском Thick (Eager Zeroed), чтобы дескриптор VMDK создался автоматически и не приходилось высчитывать цилиндры вручную.
- Подключаемся к хосту через WinSCP и заменяем существующий файл:
Все честно: футер на месте. - Включаем ВМ и видим, что ОС без проблем загрузилась. Осталось только установить VMware Tools, что будет просто, так как Convert-WindowsImage позволяет нам установить драйверы устройств.
- Переместим диск на другой Datastore через Storage vMotion с конвертацией его в тонкий диск.
- Проверяем размер – диск стал тонким.
- Если мы проведем обратную конвертацию в толстый диск или смигрируем ВМ на файловое хранилище, то получим чистейший RAW без заголовков.
Футер отрезался.
Тот же самый фокус работает и для RAW, созданных через dd. И даже в обратном направлении. Таким образом вы видите, что VMware ESXi принимает диски с футерами или RAW, созданные сторонними средствами.
Если не хочется фокусов, то можно воспользоваться инструментами ниже.
Исходный формат |
Целевой формат |
Инструменты |
Пример команды |
VHD |
VHDX |
vhdxtool.exe |
vhdxtool upgrade -f <имя файла>.vhd |
VMDK (RAW) |
VHD |
vhdtool.exe |
vhdtool /convert <имя файла flat>.vmdk |
VMDK (RAW) |
VHDX |
vhdtool.exe vhdxtool.exe |
vhdtool /convert <имя файла flat>.vmdk |
VHDX (RAW) |
VHDX |
vhdxtool upgrade -f <имя файла>.vhd |
Подведем итоги. Различные форматы толстых виртуальных дисков не такие уж разные. В основе всего RAW с различными “добавками”.
Конвертация форматов виртуальных дисков — это не страшно, и, как я показал, иногда можно обходиться даже без нее.
Основной профит всего этого — сокращение времени миграции с Hyper-V на VMware и обратно и времени простоя ВМ при миграции. В DataLine мы такое практикуем с простоем ВМ менее 30 минут. Рекорд же — 40 секунд простоя ВМ при миграции между гипервизорами.
Только помните, что при миграции между разными гипервизорами одной конвертации недостаточно. Как минимум нужно предварительно поставить компоненты интеграции целевого гипервизора, удалить или отключить запуск компонентов исходного гипервизора, удалить виртуальные устройства исходного гипервизора и т.д. Но это уже совсем другая история, о которой я тоже могу рассказать.
Полезные ссылки:
- habr.com/ru/company/acelab/blog/262517
- www.vmware.com/app/vmdk/?src=vmdk
- faq.sanbarrow.com/index.php?action=artikel&cat=43&id=36&artlang=en
- download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
- docs.microsoft.com/en-us/openspecs/windows_protocols/ms-vhdx/83e061f8-f6e2-4de1-91bd-5d518a43d477