287

У меня есть виртуальная машина VirtualBox, в которой настроен очень большой размер жесткого диска (больше, чем у хоста). По моей ошибке программа на виртуальной машине генерировала множество файлов журналов, и размер файла VDI продолжает расти, пока на хосте не останется свободного места.

Теперь я удалил файлы журналов, но размер файла VDI не уменьшается после использования VBoxManage.exe modifyhd "C:\Virts\mybox-i386.vdi" compact

Есть ли способ действительно сжать размер файла VDI? Спасибо!

8 ответов8

484

Вы должны сделать следующие шаги:

  1. Запустите defrag в гостевой системе (только для Windows)
  2. Обнулить свободное пространство:

    С гостем Linux запустите это:

    dd if=/dev/zero of=/var/tmp/bigemptyfile bs=4096k ; rm /var/tmp/bigemptyfile
    

    Или же:

    telinit 1
    mount -o remount,ro /dev/sda1
    zerofree -v /dev/sda1
    

    С гостем Windows загрузите SDelete от Sysinternals и запустите это:

    sdelete.exe c: -z
    

    (замените C: на букву диска VDI)

  3. Отключение гостевой ВМ

  4. Теперь запустите команду modifymedium VBoxManage с параметром --compact :

    С хостом Linux запустите это:

    vboxmanage modifymedium --compact /path/to/thedisk.vdi
    

    С хостом Windows запустите это:

    VBoxManage.exe modifymedium --compact c:\path\to\thedisk.vdi
    

    С хостом Mac запустите это:

    VBoxManage modifymedium --compact /path/to/thedisk.vdi
    

Это уменьшает размер VDI.

36

Если выполнение команды в принятом ответе выдает бесполезное сообщение об ошибке, подобное этому

VBoxManage.exe: error: Cannot register the hard disk 'thedisk.vdi'
{aaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeeee} because a hard disk 'thedisk.vdi'
with UUID {aaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeeee} already exists

Просто запустите команду по UUID вместо имени файла:

VBoxManage.exe modifyhd {aaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeeee} --compact
11

Я на хосте Windows 7 с гостями Windows. Вот пакетный файл, который я записал в Compact все VDI в дереве папок.

echo off
mode con:cols=140 lines=200
cls
:: see https://forums.virtualbox.org/viewtopic.php?p=29272#p29272
:: How can I reduce the size of a dynamic VDI on disk?
:: but that page says to use sdelete -s which is suboptimal. 
:: use -z as per http://technet.microsoft.com/en-us/sysinternals/bb897443.aspx

:: First run the sdelete -z c: inside the VMs that zero-out all the free space
:: THEN run this batch file 

Title Compacting Free space on Virtual Machine VMs

:: http://ss64.com/nt/for_r.html
:: http://stackoverflow.com/questions/8836368/windows-batch-file-how-to-loop-through-files-in-a-directory/8836401#8836401

Setlocal EnableDelayedExpansion
:: http://ss64.com/nt/delayedexpansion.html ... 
:: Notice that within the for loop we use !variable! instead of %variable%.

For /R %CD% %%G IN (*.vdi) DO (
 set ohai=%%G
 set lastfive=!ohai:~-5!
:: Skip snapshots which are named {guid}.vdi
 if NOT !lastfive!==}.vdi (
 echo .
 echo Compacting %%G
 "C:\Program Files\Oracle\VirtualBox\VboxManage.exe" modifyhd "%%G" --compact )
 )

pause 
exit

Я оставил ссылки в комментариях, чтобы вы могли (вроде) рассказать, как это работает.

редактировать

Что ж, после всего этого я попробовал инструмент CloneVDI, и он отлично справился с задачей за гораздо меньшее время и в один клик.

6

Гость Debian на хосте Windows с использованием discard/TRIM.

Это не прямой ответ сам по себе, так как я решаю проблему, а не вопрос. Вместо того, чтобы периодически сжимать образ, это решение использует Discard для автоматического удаления неиспользуемых блоков в образе диска виртуальной машины хоста.

Это решение требует гостевой файловой системы, которая поддерживает непрерывную TRIM. Вики Linux Arch содержит список файловых систем, поддерживающих операции TRIM.

FDE и cryptoroot специально не рассматриваются, так как существуют проблемы безопасности, и ни одно из других решений этого вопроса не позволит также сжать. Вики Linux Arch содержит информацию об устройствах TRIM и dm-crypt.

Теоретически, это будет работать для всех гостей Linux на хостах VBox, использующих хранилище VDI.

Конфигурация хоста

Когда VBox завершен, а виртуальные машины не запущены, добавьте поддержку Discard на свои диски, установив discard и nonrotational для каждого диска в файле конфигурации для VM. В настоящее время discard отсутствует в графическом интерфейсе, но не nonrotational как флажок «Твердотельный накопитель». (ссылка: форумы vbox, поддержка отмены)

<AttachedDevice discard="true" nonrotational="true" type="HardDisk" [..other options..] >

Загрузите виртуальную машину и убедитесь, что включена поддержка TRIM:

sudo hdparm -I /dev/sda | grep TRIM

Гостевая конфигурация

Если LVM используется, измените настройку сброса в /etc/lvm/lvm.conf . (ссылка: Debian Wiki, пример lvm.conf)

devices {
...
    issue_discards = 1
}

В fstab добавьте опцию discard к файловым системам, которые вы хотите автоматически удалить (ref: debian wiki, пример fstab)

UUID=8db6787f-1e82-42d8-b39f-8b7491a0523c   /   ext4    discard,errors=remount-ro   0   1
UUID=70bfca92-8454-4777-9d87-a7face32b7e7   /build  ext4    discard,errors=remount-ro,noatime   0   1

Перемонтируйте файловые системы, чтобы они выбрали новые параметры.

sudo mount -o remount /
sudo mount -o remount /build

Обрежьте свободные блоки вручную с помощью fstrim . fstrim использует смонтированную файловую систему, а не блочное устройство, поддерживающее ее. Вместо установки непрерывного сброса в fstab , это можно сделать на еженедельном кроне. (Еженедельный cron рекомендуется для физических твердотельных накопителей, которые могут иметь сомнительную поддержку TRIM, но здесь это не актуально, поскольку базовые твердотельные накопители обрабатываются операционной системой хоста. См. Предупреждение об ssd trim).

fstrim /
fstrim /build

На этом этапе размер файловых систем внутри ВМ и размер образов ВМ должны быть довольно близки по значению.

Протестировано с:

  • Гость1: Debian 8.7, ядро: linux 4.8 grsec от backports, файловая система: ext4
  • Гость 2: Debian 9 RC2, ядро: linux 4.9, файловая система: ext4
  • Host1: VBox 5.1.14, Win7, образ fmt: VDI
  • Хост 2: VBox 5.1.14, Win8.1, образ fmt: VDI
2

Для гостя MacOS сделайте это:

  1. Обнулить свободное место в гостевой системе:

    diskutil secureErase freespace 0 "/Volumes/Macintosh HD"
    

    (замените /Volumes /Macintosh HD на имя вашего диска)

  2. Отключение гостевой ВМ

  3. Запустите эту команду, чтобы уменьшить размер образа диска VDI

    VBoxManage modifyhd /path/to/thedisk.vdi --compact
    

    ИЛИ ЖЕ

    VBoxManage modifymedium /path/to/thedisk.vdi --compact
    
1

Я не хочу включать поддержку TRIM в ОС, потому что каждое удаление данных вызывает сжатие данных в файле VDI, делая гостевую систему непригодной для использования, когда файл VDI находится на классическом ротационном диске. Для меня лучше выполнять сжатие вручную, например, раз в месяц.

При обычном сжатии содержимое файла VDI копируется в новый файл. Это требует некоторого (иногда большого) свободного места на диске хоста.

У меня есть решение, аналогичное указанному Эндрю Домашек. Это работает очень хорошо даже с NTFS (Windows10).

Сделать это:

  • создайте новую виртуальную машину, которая загружается с GParted Live CD (вы можете использовать ваш любимый дистрибутив Linux).
  • Отредактируйте настройки машины и установите контроллер диска SATA
  • Добавьте существующие файлы VDI, которые вы хотите сжать
  • Измените диски на основе VDI, чтобы они отображались как SSD с поддержкой TRIM:

VBoxManage storageattach "gpared live" --storagectl "SATA" --port 0 --discard on --nonrotational on VBoxManage storageattach "gpared live" --storagectl "SATA" --port 1 --discard on --nonrotational on

  • запустить машину
  • В корневой оболочке Linux смонтируйте раздел NTFS mount /dev/sda2 /mnt
  • ноль свободного места dd if=/dev/zero of=/mnt/bigfile
  • rm /mnt/bigfile
  • принудительное сжатие VDI без создания нового файла: fstrim -v /mnt
1

Я использую это для моего образа VDI, подключенного к виртуальному Debian в Windows VirtualBox. Это не общее решение, но оно должно по крайней мере дать вам представление о том, что я делаю.

Команды в Debian:

root@debian:~# lsblk  # show partitions
NAME MAJ:MIN RM РАЗМЕР RO ТИП MOUNTPOINT SDB 8:16 0 128G 0 диск └─sdb1 8:17 0 128G 0 part /mnt /web # ЭТО РАЗДЕЛ ИНТЕРЕСА!
sda 8:0 64G 0 диск ├─sda1 8:1 0 61,4G 0 part / ├─sda2 8:2 0 1K 0 part └─sda5 8:5 0 2,7G 0 part [SWAP] sr0 11:0 1 56,3M 0 rom
root@debian:~# service mysql stop  # terminate all operations with partition
root@debian:~# service apache2 stop  # terminate all operations with partition
root@debian:~# umount /mnt/web  # unplug partition
root@debian:~# apt-get install zerofree  # install tool for filling in zeros to empty space
root@debian:~# zerofree -v /dev/sdb1  # fill with zeros
root@debian:~# poweroff  # shut down machine

Команды в Windows:

C:\Program Files\Oracle\VirtualBox>VBoxManage.exe modifyhd --compact "D:\VirtualBox VMs\web.vdi"  # convert zeros to empty space

Надеюсь, поможет :)

0

Очень приятный трюк в дополнение к принятому ответу состоит в том, что вы можете обойтись без какого-либо уплотнения после обнуления гостевого пространства, используя сжатую файловую систему на хосте (например, выбор сжатия папки виртуальных дисков в свойствах NTFS на Windows хост). Это на самом деле имеет преимущество, позволяющее сэкономить гораздо больше места, потому что операционные системы, как правило, содержат много повторяющихся текстовых или двоичных файлов (например, гостевой диск на 30 ГБ, на котором было обнулено 15 ГБ свободного места, может превратиться в 4 ГБ на главном диске).

Предостережения включают в себя то, что доступ к диску на реальном оборудовании может увеличиться, а загрузка ЦП немного увеличивается.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .