Відхід від VMware після Broadcom: перевірений план міграції

Відхід від VMware після Broadcom: перевірений план міграції

Відхід від VMware після Broadcom: перевірений план міграції

Коротко (перевірено 2026-11-03): після купівлі VMware компанія Broadcom припинила продаж безстрокових ліцензій, звела лінійку продуктів до двох пакетів за підпискою, закрила стару програму хмарних партнерів у Європі, а цієї осені прибрала з публічного доступу VDDK - бібліотеку для роботи з дисками, через яку більшість інструментів міграції читає диски VMware. Сьогодні The Register повідомляє про відкриту заміну цієї бібліотеки, що працює лише на читання. Втім, не кожен шлях виходу потребує VDDK: експорт в OVA плюс конвертація диска взагалі не використовують код VMware. Нижче: зміни з датами, реалістичні цільові платформи для команди в ЄС, покроковий переїзд і конвертер, який ми запустили на справжньому експорті у форматі VMware.

Джерело. "Architect creates open-source replacement for VM migration tool VMware has hidden" (Simon Sharwood, The Register, 2026-11-03). Інші факти мають посилання там, де згадуються. Ваш власний договір може відрізнятися від публічних умов, тож уточнюйте деталі ліцензування у свого реселера.

Що змінила Broadcom: хронологія

Дата Зміна Джерело
2023-12-11 Кінець продажу безстрокових ліцензій і продовження підтримки; пропозицію скорочено до підписок VMware Cloud Foundation (VCF) і vSphere Foundation (VVF) Новини Broadcom, Krish Prasad
2025-03-28 Дистриб'ютор Arrow повідомляє партнерам, що з 2025-04-10 мінімальне замовлення зростає з 16 до 72 ядер на продуктову лінійку The Register
2026-01-26 Договори хмарних провайдерів (VCSP) в ЄЕЗ не продовжуються; відкриті угоди треба закрити до 2026-03-31; далі програма лише за запрошеннями The Register, 2026-01-31
Aug-Sep 2026 VDDK прибрано з публічного завантаження: "The VDDK is not a customer entitlement" (VDDK не входить у права клієнта), доступ через окремих партнерів TAP TechTarget, 2026-09-09
2026-11-03 OpenVDDK від Andrija Panić: сумісна заміна libvixDiskLib.so.8.0.3 лише для читання під ліцензією Apache, яка "contains no VMware code" (не містить коду VMware) The Register, 2026-11-03

Два застереження. Про мінімум у 72 ядра повідомив дистриб'ютор, а не сторінка Broadcom, яку нам вдалося знайти: стаття Broadcom про підрахунок ядер (KB 313548, перевірено 2026-11-03) каже "You must license a minimum of 16 physical cores for each CPU" (потрібно ліцензувати щонайменше 16 фізичних ядер на кожен CPU), а деякі реселери стверджують, що мінімальне замовлення у 72 ядра знову скасували. Просіть письмово вказати кількість ядер у комерційній пропозиції. До того ж європейська історія ще не завершена: у липні 2025 року галузеве об'єднання хмарних провайдерів CISPE звернулося до Загального суду ЄС з вимогою скасувати схвалення злиття Єврокомісією (справа T-503/25); рішення ми поки не знайшли.

Чому VDDK важливий і які шляхи без нього обходяться

Бібліотека VDDK, libvixDiskLib, дає інструменту змогу читати диски ВМ, які ще працюють у vSphere. The Register називає серед інструментів, що її завантажують, virt-v2v, nbdkit, імпортери Forklift / MTV, Apache CloudStack і власні скрипти компаній. Розширення Microsoft VM Conversion для Windows Admin Center (з vCenter у Hyper-V, з теплою синхронізацією через Change Block Tracking) досі позначене як preview у його документації (оновлено 2026-02-20), а матеріали про запуск називають VDDK серед передумов. OpenVDDK - новий варіант для всіх них, хоча автор сам попереджає, що звіти тестувальників "not independently audited customer endorsements" (не є незалежно перевіреними відгуками клієнтів).

Шляхи взагалі без VDDK, згідно з документацією virt-v2v щодо введення з VMware (перевірено 2026-11-03): експорт OVA (-i ova), файли ВМ на NFS або через SSH (-i vmx, -it ssh), NFC і звичайний шлях через vCenter HTTPS, який документація називає "the slowest method" (найповільніший спосіб). Майстер імпорту ESXi у Proxmox VE, анонсований 2024-03-27, читає диски через ESXi API за допомогою власної файлової системи користувацького простору на Rust і був протестований з ESXi від 6.5 до 8.0 (форум Proxmox).

Куди переїжджати: п'ять реалістичних варіантів

Цільова платформа Підходить, коли На що зважати
Proxmox VE (KVM) на вашому обладнанні 3+ хости, команда хоче GUI і кластеризацію Оновлення, сховище (ZFS, Ceph) і підтримка на вас
OpenStack Багато орендарів, усе через API Важкий в експлуатації; окупається лише на масштабі
Hyper-V (Windows Server) Переважно Windows, ліцензії Datacenter уже оплачені Інструменту Microsoft спершу потрібні драйвери Hyper-V у гостьових Linux
Хмарні сервери (KVM) Від кількох до кількох десятків ВМ, без бажання обслуговувати гіпервізор Один імпорт на кожну ВМ, нові IP-адреси
Виділені сервери + власний гіпервізор Стабільне навантаження, потрібна вся машина Гіпервізор ви експлуатуєте й оновлюєте самі

Перенесення ВМ за п'ять кроків

  1. Інвентаризація та прибирання. Зафіксуйте прошивку (BIOS чи EFI), контролер диска, тип мережевої карти, статичні IP і будь-яку ліцензію, прив'язану до MAC-адреси. Видаліть або консолідуйте знімки, щоб експортувати один актуальний диск.
  2. Підготуйте гостьову систему, поки вона ще працює на VMware. Windows: встановіть драйвери virtio (virtio-win) зараз; гостьова Windows, перенесена на диск virtio без них, не завантажиться. Linux: драйвери virtio є в ядрі, але initramfs у режимі host-only може їх не містити; перевірте через lsinitramfs або lsinitrd і за потреби перезберіть його.
  3. Експорт або підключення. Вимкніть ВМ і експортуйте OVF / OVA (у vSphere Client "Export OVF Template" або через ovftool), або дозвольте virt-v2v чи майстру Proxmox забрати її самостійно.
  4. Конвертація. Лише диск - через qemu-img, усю гостьову систему - через virt-v2v (він також налаштовує драйвери), або напряму в Proxmox з OVF.
  5. Завантаження через консоль, потім прибирання. Перевірте ім'я мережевого інтерфейсу та IP, видаліть VMware Tools або open-vm-tools, встановіть qemu-guest-agent.
qemu-img convert -p -f vmdk -O qcow2 disk1.vmdk disk1.qcow2
virt-v2v -i ova VM.ova -o local -os /var/tmp -of qcow2
qm importovf 120 VM.ovf local-lvm

Це задокументовані форми з посібника кожного інструмента; ці три команди ми тут не запускали. Конвертацію, яку ми справді запустили, наведено нижче.

Перевірено: що насправді робить конвертація (ova2raw.js)

Щоб показати, з чого складається процес, ми написали конвертацію приблизно в 100 рядках на Bun без залежностей. Скрипт відкриває OVA (звичайний tar), перевіряє маніфест SHA-256, виводить обладнання, яке вимагає OVF, розпаковує streamOptimized VMDK зерно за зерном у розріджений raw-образ і перевіряє GPT. Ми подали йому офіційний OVA Ubuntu 24.04, справжній експорт у форматі VMware: noble-server-cloudimg-amd64.ova, збірка від 2026-10-17, SHA-256 якої збігся з SHA256SUMS від Ubuntu. Збережіть як ova2raw.js:

// ova2raw.js - check a VMware OVA export and turn its disk into a raw image for KVM
// usage: bun ova2raw.js <export.ova> <out.raw>
import { openSync, readSync, writeSync, ftruncateSync, closeSync, fstatSync } from 'node:fs'
import { inflateSync } from 'node:zlib'
import { createHash } from 'node:crypto'

const [ova, out] = process.argv.slice(2)
const fd = openSync(ova, 'r')
const read = (pos, len) => {
  const b = Buffer.alloc(len)
  readSync(fd, b, 0, len, pos)
  return b
}

// 1. an OVA is a plain tar: list its members
const files = {}
for (let o = 0; o + 512 <= fstatSync(fd).size; ) {
  const h = read(o, 512)
  if (h.every(x => x === 0)) break
  const name = h.toString('utf8', 0, 100).replace(/\0.*$/s, '')
  const size = parseInt(h.toString('ascii', 124, 136).replace(/\0.*$/s, '').trim(), 8)
  files[name] = { pos: o + 512, size }
  o += 512 + Math.ceil(size / 512) * 512
}
const find = ext => Object.keys(files).find(n => n.endsWith(ext))
const text = n => read(files[n].pos, files[n].size).toString('utf8')
console.log('OVA members:', Object.entries(files).map(([n, f]) => `${n} (${f.size} B)`).join(', '))

// 2. the .mf manifest: every member's SHA-256 must match
const mf = find('.mf')
for (const line of mf ? text(mf).split('\n') : []) {
  const m = line.match(/^SHA(1|256)\((.+)\)\s*=\s*([0-9a-f]+)/i)
  if (!m || !files[m[2]]) continue
  const h = createHash('sha' + m[1])
  const f = files[m[2]]
  for (let p = 0; p < f.size; p += 1 << 24) h.update(read(f.pos + p, Math.min(1 << 24, f.size - p)))
  console.log(`  manifest ${m[2]}: ${h.digest('hex') === m[3].toLowerCase() ? 'OK' : 'MISMATCH'}`)
}

// 3. the .ovf descriptor: what the VM expects from its hardware
const ovf = text(find('.ovf'))
const items = [...ovf.matchAll(/<(?:ovf:)?Item\b[\s\S]*?<\/(?:ovf:)?Item>/g)].map(x => x[0])
const tag = (s, t) => s.match(new RegExp(`<(?:rasd:)?${t}>([^<]*)<`))?.[1]
const kind = { 3: 'CPU', 4: 'RAM', 5: 'IDE controller', 6: 'SCSI controller', 10: 'NIC', 17: 'disk', 20: 'SATA controller' }
console.log('OVF:', ovf.match(/vmw:osType="([^"]+)"/)?.[1] ?? '?', '| firmware',
  ovf.match(/key="firmware" ovf:value="([^"]+)"/)?.[1] ?? 'bios (default)')
for (const it of items) {
  const k = kind[tag(it, 'ResourceType')]
  if (k) console.log(`  ${k.padEnd(16)} ${tag(it, 'ElementName') ?? ''} ${tag(it, 'ResourceSubType') ?? ''} ${tag(it, 'VirtualQuantity') ?? ''}`.trimEnd())
}

// 4. the streamOptimized VMDK: a header, then compressed grains and markers
const vmdk = files[find('.vmdk')]
const hd = read(vmdk.pos, 512)
if (hd.readUInt32LE(0) !== 0x564d444b) throw new Error('not a sparse VMDK (no KDMV magic)')
const capacity = Number(hd.readBigUInt64LE(12)) * 512
const desc = read(vmdk.pos + Number(hd.readBigUInt64LE(28)) * 512, Number(hd.readBigUInt64LE(36)) * 512)
console.log(`VMDK ${desc.toString().match(/createType="([^"]+)"/)?.[1]}, virtual size ${capacity} B, grain ${Number(hd.readBigUInt64LE(20)) * 512} B`)

const ofd = openSync(out, 'w')
ftruncateSync(ofd, capacity) // sparse: unwritten grains stay holes = zeros
let pos = Number(hd.readBigUInt64LE(64)) * 512
let grains = 0
let written = 0
while (pos < vmdk.size) {
  const m = read(vmdk.pos + pos, 512)
  const val = Number(m.readBigUInt64LE(0))
  const size = m.readUInt32LE(8)
  if (size) { // compressed grain: lba, size, zlib data
    const raw = inflateSync(read(vmdk.pos + pos + 12, size))
    writeSync(ofd, raw, 0, raw.length, val * 512)
    grains++
    written += raw.length
    pos += Math.ceil((12 + size) / 512) * 512
  } else if (m.readUInt32LE(12) === 0) break // end-of-stream marker
  else pos += 512 + val * 512 // grain table / directory / footer: metadata only
}
closeSync(ofd)
console.log(`Wrote ${out}: ${grains} grains, ${written} B of data in ${capacity} B`)

// 5. check the result: a valid GPT, and the file systems where the partitions say they are
const rfd = openSync(out, 'r')
const at = (p, l) => { const b = Buffer.alloc(l); readSync(rfd, b, 0, l, p); return b }
const gpt = at(512, 92)
const crc = Buffer.from(gpt)
crc.writeUInt32LE(0, 16)
console.log(`GPT "${gpt.toString('ascii', 0, 8)}", header CRC ${(Bun.hash.crc32(crc) >>> 0) === gpt.readUInt32LE(16) ? 'OK' : 'BAD'}`)
const n = gpt.readUInt32LE(80)
const es = gpt.readUInt32LE(84)
const ents = at(Number(gpt.readBigUInt64LE(72)) * 512, n * es)
console.log(`  partition array CRC ${(Bun.hash.crc32(ents) >>> 0) === gpt.readUInt32LE(88) ? 'OK' : 'BAD'}`)
for (let i = 0; i < n; i++) {
  const e = ents.subarray(i * es, (i + 1) * es)
  if (e.subarray(0, 16).every(x => x === 0)) continue
  const first = Number(e.readBigUInt64LE(32))
  const last = Number(e.readBigUInt64LE(40))
  const sb = at(first * 512 + 1024, 136)
  const fs = sb.readUInt16LE(56) === 0xef53 ? `ext4 label "${sb.toString('ascii', 120, 136).replace(/\0.*$/s, '')}"`
    : at(first * 512, 512).toString('ascii', 82, 87) === 'FAT32' ? 'FAT32 (EFI system partition)'
    : e.toString('ascii', 0, 16) === 'Hah!IdontNeedEFI' ? 'BIOS boot (GRUB for legacy BIOS)' : 'unknown'
  console.log(`  p${i + 1} ${String((last - first + 1) * 512 / 2 ** 20 | 0).padStart(5)} MiB  ${fs}`)
}
bun ova2raw.js noble-server-cloudimg-amd64.ova noble.raw

Результат, запущено на хмарному сервері DCXV з Bun 1.4.4 2026-11-03:

OVA members: ubuntu-noble-24.04-cloudimg.ovf (11186 B), ubuntu-noble-24.04-cloudimg.mf (213 B), ubuntu-noble-24.04-cloudimg.vmdk (590749696 B)
  manifest ubuntu-noble-24.04-cloudimg.vmdk: OK
  manifest ubuntu-noble-24.04-cloudimg.ovf: OK
OVF: ubuntu64Guest | firmware bios (default)
  CPU              2 virtual CPU(s)  2
  RAM              1024MB of memory  1024
  SCSI controller  SCSI Controller 0 VirtualSCSI
  IDE controller   VirtualIDEController 1
  IDE controller   VirtualIDEController 0
  disk             Hard Disk 1
  NIC              Ethernet 1 VmxNet3
VMDK streamOptimized, virtual size 10737418240 B, grain 65536 B
Wrote noble.raw: 28663 grains, 1878458368 B of data in 10737418240 B
GPT "EFI PART", header CRC OK
  partition array CRC OK
  p1  2558 MiB  ext4 label "cloudimg-rootfs"
  p14     4 MiB  BIOS boot (GRUB for legacy BIOS)
  p15   106 MiB  FAT32 (EFI system partition)
  p16   913 MiB  ext4 label "BOOT"

Три запуски тривали від 14.6 до 16.2 s реального часу на цьому сервері. Raw-файл має розмір 10 GiB і займає 1.8 GB на диску.

Що вивід підказує ще до перемикання

  1. VmxNet3 і VirtualSCSI - це пристрої VMware. На KVM вони стають virtio-net та virtio-blk або virtio-scsi. Гостьовій системі потрібні драйвери для обох ще до першого завантаження, а мережевий інтерфейс зазвичай отримує нове ім'я, тож статичний IP, прив'язаний до старого імені, не підніметься. Перше завантаження робіть через консоль.
  2. Прошивка має збігатися. Цей OVF нічого не задає, отже це BIOS; на диску є і розділ BIOS boot, і системний розділ EFI, тож він завантажиться в будь-якому разі. ВМ, експортованій з firmware=efi, на цільовій платформі потрібен UEFI (OVMF), інакше вона не знайде завантажувач.
  3. Тонкий диск лишається тонким, лише якщо ви це забезпечите. 10 GiB віртуально, 1.8 GB даних. Копіюйте інструментами, що враховують розрідженість (cp --sparse=always, rsync -S), або використовуйте qcow2, інакше ви передаватимете й зберігатимете нулі.
  4. Маніфест - ваша перевірка передачі. Звіряйте SHA-256 після кожного копіювання між майданчиками: обірване завантаження без жодних скарг конвертується в диск, який збоїть пізніше.

Плануйте простій

Холодний переїзд коштує: експорт + передача + конвертація + перше завантаження. Заміряйте кожен етап на одній тестовій ВМ, потім помножте. Арифметика передачі (наша, без накладних витрат протоколу): 1.8 GB на 1 Gbit/s - це близько 15 s, 1 TB - близько 2.2 години. Теплі інструменти копіюють, поки ВМ працює, і наприкінці надсилають лише змінені блоки; тестувальники The Register повідомляють про холодні й теплі прогони з Forklift і MTV. Для баз даних і навантажених застосунків реплікація плюс перемикання DNS кращі за будь-яке копіювання дисків: спершу зменшіть TTL (див. поширення DNS і TTL) і пройдіть чеклісти з інструкції з міграції на хмарний сервер.

Коли підходять хмарні або виділені сервери DCXV

  • Кілька ВМ, без команди для гіпервізора: наші хмарні сервери працюють на KVM з дисками virtio. У панелі Перевстановлення -> "Власний образ (URL)" приймає файл qcow2, raw або vmdk через https; образ, більший за диск тарифу, збільшує диск і тарифікується як розширення диска, а мережеві налаштування застосовуються лише тоді, коли в образі є cloud-init. Тарифи від EUR 15.00/міс (2 vCPU, 4 GB RAM, 40 GB; перевірено 2026-11-03, без ПДВ).
  • Десятки ВМ або власний кластер Proxmox: виділені сервери від EUR 210/міс з гіпервізором на ваш вибір.
  • Гостьові Windows: ми перепродаємо ліцензії Windows Server; зверніться до переїзду, щоб ліцензія була готова з першого дня.

Обидва варіанти працюють у наших дата-центрах Tier III у Празі та Ковільї.

Сплануйте переїзд разом з нами

Запустіть ova2raw.js на одній експортованій ВМ і надішліть рядки з обладнанням з його виводу на sales@dcxv.com, або запустіть хмарний сервер і перевірте імпорт самостійно.

Відхід від VMware після Broadcom: перевірений план міграції
clouddedicatedinfrastructure

Відхід від VMware після Broadcom: перевірений план міграції

Broadcom скасував безстрокові ліцензії, урізав партнерів і сховав VDDK. Як перенести ВМ на KVM, Proxmox чи Hyper-V: дати, факти і перевірений конвертер OVA.

Час поширення DNS: 3 секунди Cloudflare проти вашого TTL
networkingcloudinfrastructure

Час поширення DNS: 3 секунди Cloudflare проти вашого TTL

Cloudflare скоротив затримку збірки DNS до 3,3 с. Але переїзд на новий сервер чекає на TTL, негативний кеш і делегування .com на 2 дні. Виміряно на двох зонах.

Що 10 000 коментарів у радах США означають для клієнтів ЦОД
clouddedicatedinfrastructure

Що 10 000 коментарів у радах США означають для клієнтів ЦОД

Новий датасет описує 10 202 виступи в радах США про дата-центри: 90,5% проти, вода на першому місці. Ми перерахували дані й пояснюємо, що це дає клієнтам.

Підтримка і рахунки AWS: перевірений гайд для команд з ЄС
cloudpricingcompare

Підтримка і рахунки AWS: перевірений гайд для команд з ЄС

Плани підтримки AWS і ціни, затримки білінгу, egress з Франкфурта, скрипт перевірки витрат і коли європейський провайдер з фіксованою ціною підходить краще.

Затримка пам'яті на хмарному сервері: виміряно, а не вгадано
clouddedicatedinfrastructure

Затримка пам'яті на хмарному сервері: виміряно, а не вгадано

Популярний пост стверджує, що зайнятий CPU часто просто чекає на RAM. Ми виміряли затримку від L1 до DRAM на нашому хмарному сервері й пояснюємо, що це дає.