Вам когда-нибудь доводилось уменьшать размер qcow2 образа диска, используемого в виртуальных машинах KVM-QEMU? Как известно, процесс увеличения размера образа довольно прост и быстр, а как обстоят дела с уменьшением?
В данной статье я расскажу про ситуацию, когда нужно уменьшить qcow2 образ виртуальной машины KVM в максимально быстрые сроки.
Формат блочных устройств — qcow2
Но, тем не менее, эту схему можно проделать и с raw образами, достаточно сконвертировать его в qcow2. В общем-то, инструкция будет актуальна для всего, что конвертируется в qcow2.
Простой способ уменьшения диска на KVM заключается в следующих этапах:
Хост: CentOS 7 + QEMU 2.12 + LIBVIRT 4.5.0 + Kernel UEK5 v. 4.14
VM: CentOS 7 + 80GB HDD + Kernel std v. 3.10
В качестве донора будет выступать виртуальная машина CentOS 7 с образом жесткого диска размером 80GB, фактически занимаемыми 20GB и физически 80GB. Уменьшать будем до 40GB.
В чем разница между размером образа, фактическим и физическим объемом?
Допустим, qcow2 image создан размером 80гб и мы об этом знаем. В процессе эксплуатации образ забивался данными, какие-то данные удалялись. Если в общих словах — в связи с особенностями процесса записи-удаления данных, для ОС удаленные данные как бы не существуют, а в образе остаются записанными, пока не будут перезаписаны другими данными. Соответственно хоть в ОС Вы будете видеть 20GB фактически занимаемых данных, то хост KVM покажет такую замечательную картину (используем утилиту qemu-img для получения информации):
Можно заметить что virtual size = disk size, а так же du -sh образа покажет что он занимает реальные 80G:
И так как нам нужно уменьшить размер образа до 40GB, приступаем к процессу.
Этап 1 — Сжатие блочного устройства (образа)
Перед началом процедуры уменьшения диска надо убедиться, что занимаемое пространство внутри ОС меньше объема, до которого диск будет так или иначе уменьшен.
Как мы видим, занято 18GB, что меньше 40GB. Выключаем VM командой
И переходим на хост машину, проверяем:
Для сжатия образа нам понадобится простая утилита virt-sparsify. Убедимся что VM не работает и выполним команду в директории вместе с образом диска (Важное замечание: перед началом virt-sparsify, убедитесь, что в /tmp и в хранилище образа достаточно свободного пространства для выполнения операции)
Результатом успешного завершения операции будет следующий вывод:
Затем делаем подмену диска (перемещаем qcow_shrink куда-нибудь в сторону, например qcow_shrink-old, а qcow_shrink-new на его место — qcow_shrink)
Запускаем VM. Если всё запустилось, гасим VM и продолжаем работы.
Этап 2 — Создание диска меньшего размера
Простая процедура включающая в себя всего одну команду:
qcow_shrinked — имя нового образа
40G — новый размер
Этап 3 — подключение gparted
Так как иногда админы предпочитают более легкие пути решения вопроса, бубен откладывается в сторону (kpartx) и на его место приходит ISO и VNC. К счастью, в KVM подключить его не очень сложно.
Что мы делаем:
Как это делать, я опущу из данной статьи, так как подразумевается что выполняющий всё это уже знает, как это происходит, но результатом будет следующее:
Запускаем VM и видим загрузочный экран GParted:
Выбираем первый пункт и следуем инструкциям на экране. Я обычно нажимаю enter до конца.
Увидев сам GParted, приступаем к действу. Быстренько проверяем какая у /dev/vda таблица разделов — msdos или gpt. Это важно:
Переключаемся на второй диск /dev/vdb и создадим таблицу разделов:
При создании таблицы выбираем тип msdos как мы узнали ранее.
Затем переключаемся обратно на /dev/vda и последовательно, с первых дисков начинаем копировать разделы переключаясь между vda и vdb:
Конечным результатом будет:
Нажимаем Apply и ждем завершения результата:
В результате:
Что уже похоже на правду. Но так как мы сделали некоторые манипуляции, которые приведут к изменению UUID дисков, мы потенциально не загрузимся в ОС. Почему? CentOS 7 использует в fstab UUID дисков, Grub2 использует UUID дисков, поэтому прыгаем в консоль и занимаемся черной магией.
Gparted работает изначально под пользователем, поэтому прыгаем под root командой sudo su — root:
Сделаем blkid чтобы убедится, что UUID разделов поменялся
Видно, что UUID vda1 = vdb1, а у vdb2 он поменялся. Ничего страшного — жить с этим можно.
Монтируем vdb полностью, вместе с /boot разделом, а также смонтируем некоторые разделы для нашего удобства.
Начнем с fstab — так как в VNC набирать UUID не очень удобно, заменим его на привычное название устройства.
Заменяем строку с UUID=… на, внимание:
указываем /dev/vdb2, если старый диск не планируется отключать
указываем /dev/vda2, если старый диск будет отключен
Так как мы старый диск отключаем перед загрузкой ОС, то пишем /dev/vda2
Далее изменим загрузчик, приведем его в порядок. Предположим, что всё лежит штатно в /boot/grub2, grub.cfg там же, а efi нет (msdos table, какой efi :) ):
На этом можно порадоваться за себя и отключив gparted, загрузиться в ОС.
Этап 4 — загрузка ОС
Перед загрузкой ОС я всё же рекомендую отключить старый диск от сервера. Поэтому на предыдущем этапе в fstab нужно было прописать vda2, но если Вы внимательный пользователь ПК и ничего не отключали, то проблем возникнуть не должно. Со старым диском велика вероятность загрузиться именно с него.
В процессе загрузки никаких проблем не возникло, сервер загрузился как положено. Проверим это:
Мы видим, что /boot и / нужные, размер 40GB, ОС работает. Счастье, не иначе!
Бонус
То, с чем придется столкнуться в некоторых ситуациях.
Скорее всего, когда всё делалось в gparted или ином окружении, версия ядра этого окружения была слишком новой, в котором xfs немного изменен, а именно отличаются метаданные и их версия. В результате xfs сделанный в новом ядре, превращается в тыкву на старом. Что делаем — загружаемся обратно в rescue gparted, поднимаем в этом rescue окружении сеть и ставим максимально свежее ядро в ОС. Я ставил 5.х на CentOS 7, возможно подойдет и 4.х, не проверял, но в итоге всё работало. Причем, без особых проблем.
На этом всё!
Как видите, ничего сложного в этом нет. Конечно, можно использовать LVM, resize2fs и прочие штуки, но всё-таки qcow2 где-то ещё используется и кому-то даже нужен.
Если вы знаете способ ещё более простой — напишите о нём в комментариях.
В данной статье я расскажу про ситуацию, когда нужно уменьшить qcow2 образ виртуальной машины KVM в максимально быстрые сроки.
Формат блочных устройств — qcow2
Но, тем не менее, эту схему можно проделать и с raw образами, достаточно сконвертировать его в qcow2. В общем-то, инструкция будет актуальна для всего, что конвертируется в qcow2.
Простой способ уменьшения диска на KVM заключается в следующих этапах:
- Сжатие блочного устройства qcow2 (диска VM)
- Создание диска меньшего размера
- Подключение gparted образа, старого и нового диска
- Подготовка к загрузке ОС
- Характеристики VM и хост машины:
Хост: CentOS 7 + QEMU 2.12 + LIBVIRT 4.5.0 + Kernel UEK5 v. 4.14
VM: CentOS 7 + 80GB HDD + Kernel std v. 3.10
В качестве донора будет выступать виртуальная машина CentOS 7 с образом жесткого диска размером 80GB, фактически занимаемыми 20GB и физически 80GB. Уменьшать будем до 40GB.
В чем разница между размером образа, фактическим и физическим объемом?
Допустим, qcow2 image создан размером 80гб и мы об этом знаем. В процессе эксплуатации образ забивался данными, какие-то данные удалялись. Если в общих словах — в связи с особенностями процесса записи-удаления данных, для ОС удаленные данные как бы не существуют, а в образе остаются записанными, пока не будут перезаписаны другими данными. Соответственно хоть в ОС Вы будете видеть 20GB фактически занимаемых данных, то хост KVM покажет такую замечательную картину (используем утилиту qemu-img для получения информации):
qemu-img info qcow2_image.img
image: qcow2_image.img
file format: qcow2
virtual size: 80G (85899345920 bytes)
disk size: 80G
cluster_size: 65536
Format specific information:
compat: 0.10
refcount bits: 16
Можно заметить что virtual size = disk size, а так же du -sh образа покажет что он занимает реальные 80G:
du -sh qcow2_image.img
80G qcow2_image.img
И так как нам нужно уменьшить размер образа до 40GB, приступаем к процессу.
Этап 1 — Сжатие блочного устройства (образа)
Перед началом процедуры уменьшения диска надо убедиться, что занимаемое пространство внутри ОС меньше объема, до которого диск будет так или иначе уменьшен.
df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/vda2 80G 18G 63G 22% /
Как мы видим, занято 18GB, что меньше 40GB. Выключаем VM командой
shutdown -h now
И переходим на хост машину, проверяем:
- сколько занимает образ физически
- сколько фактически
# qemu-img info qcow_shrink
image: qcow_shrink
file format: qcow2
virtual size: 80G (85899345920 bytes)
disk size: 80G
cluster_size: 65536
Format specific information:
compat: 0.10
refcount bits: 16
# virt-df -h qcow_shrink
du -sh Filesystem Size Used Available Use%
qcow_shrink:/dev/sda1 488M 101M 351M 21%
qcow_shrink:/dev/sda2 79G 17G 62G 22%
# du -sh qcow_shrink
80G qcow_shrink
Для сжатия образа нам понадобится простая утилита virt-sparsify. Убедимся что VM не работает и выполним команду в директории вместе с образом диска (Важное замечание: перед началом virt-sparsify, убедитесь, что в /tmp и в хранилище образа достаточно свободного пространства для выполнения операции)
virt-sparsify qcow_shrink qcow_shrink-new
Результатом успешного завершения операции будет следующий вывод:
[ 0.0] Create overlay file in /tmp to protect source disk
[ 0.1] Examine source disk
[ 1.2] Fill free space in /dev/sda1 with zero
[ 1.5] Fill free space in /dev/sda2 with zero
100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[ 72.5] Copy to destination and make sparse
[ 81.9] Sparsify operation completed with no errors.
virt-sparsify: Before deleting the old disk, carefully check that the
target disk boots and works correctly.
Затем делаем подмену диска (перемещаем qcow_shrink куда-нибудь в сторону, например qcow_shrink-old, а qcow_shrink-new на его место — qcow_shrink)
mv qcow_shrink qcow_shrink-old && mv qcow_shrink-new qcow_shrink
Запускаем VM. Если всё запустилось, гасим VM и продолжаем работы.
Этап 2 — Создание диска меньшего размера
Простая процедура включающая в себя всего одну команду:
qemu-img create -f qcow2 -o preallocation=metadata qcow_shrinked 40G
qcow_shrinked — имя нового образа
40G — новый размер
Этап 3 — подключение gparted
Так как иногда админы предпочитают более легкие пути решения вопроса, бубен откладывается в сторону (kpartx) и на его место приходит ISO и VNC. К счастью, в KVM подключить его не очень сложно.
Что мы делаем:
- Подключаем образ ISO GParted
- Подключаем qcow2_shrinked к VM
- Запускаем VM, загружаемся с ISO
Как это делать, я опущу из данной статьи, так как подразумевается что выполняющий всё это уже знает, как это происходит, но результатом будет следующее:
Запускаем VM и видим загрузочный экран GParted:
Выбираем первый пункт и следуем инструкциям на экране. Я обычно нажимаю enter до конца.
Увидев сам GParted, приступаем к действу. Быстренько проверяем какая у /dev/vda таблица разделов — msdos или gpt. Это важно:
Переключаемся на второй диск /dev/vdb и создадим таблицу разделов:
При создании таблицы выбираем тип msdos как мы узнали ранее.
Затем переключаемся обратно на /dev/vda и последовательно, с первых дисков начинаем копировать разделы переключаясь между vda и vdb:
Конечным результатом будет:
Нажимаем Apply и ждем завершения результата:
В результате:
Что уже похоже на правду. Но так как мы сделали некоторые манипуляции, которые приведут к изменению UUID дисков, мы потенциально не загрузимся в ОС. Почему? CentOS 7 использует в fstab UUID дисков, Grub2 использует UUID дисков, поэтому прыгаем в консоль и занимаемся черной магией.
Gparted работает изначально под пользователем, поэтому прыгаем под root командой sudo su — root:
Сделаем blkid чтобы убедится, что UUID разделов поменялся
Видно, что UUID vda1 = vdb1, а у vdb2 он поменялся. Ничего страшного — жить с этим можно.
Монтируем vdb полностью, вместе с /boot разделом, а также смонтируем некоторые разделы для нашего удобства.
mkdir vdb2
mount /dev/vdb2 vdb2
mount /dev/vdb1 vdb2/boot
cd vdb2
mount --bind /dev dev
mount --bind /sys sys
mount --bind /proc proc
chroot .
Начнем с fstab — так как в VNC набирать UUID не очень удобно, заменим его на привычное название устройства.
Заменяем строку с UUID=… на, внимание:
указываем /dev/vdb2, если старый диск не планируется отключать
указываем /dev/vda2, если старый диск будет отключен
Так как мы старый диск отключаем перед загрузкой ОС, то пишем /dev/vda2
Далее изменим загрузчик, приведем его в порядок. Предположим, что всё лежит штатно в /boot/grub2, grub.cfg там же, а efi нет (msdos table, какой efi :) ):
grub2-install /dev/vdb
cd /boot/grub2
grub2-mkconfig -o grub.cfg
На этом можно порадоваться за себя и отключив gparted, загрузиться в ОС.
Этап 4 — загрузка ОС
Перед загрузкой ОС я всё же рекомендую отключить старый диск от сервера. Поэтому на предыдущем этапе в fstab нужно было прописать vda2, но если Вы внимательный пользователь ПК и ничего не отключали, то проблем возникнуть не должно. Со старым диском велика вероятность загрузиться именно с него.
В процессе загрузки никаких проблем не возникло, сервер загрузился как положено. Проверим это:
[root@shrink ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 484M 0 484M 0% /dev
tmpfs 496M 0 496M 0% /dev/shm
tmpfs 496M 6.7M 489M 2% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
/dev/vdb2 40G 18G 23G 44% /
/dev/vdb1 488M 101M 352M 23% /boot
tmpfs 100M 0 100M 0% /run/user/0
[root@shrink ~]# blkid
/dev/vda1: UUID="ea505196-32fb-4df6-8bed-0a0ab2d0b726" TYPE="ext4"
/dev/vda2: UUID="30ec1bc6-658f-4611-8708-5e3b7ebaa467" TYPE="xfs"
/dev/vdb1: UUID="ea505196-32fb-4df6-8bed-0a0ab2d0b726" TYPE="ext4"
/dev/vdb2: UUID="c8548834-272b-4331-a9bf-aa99fb41a434" TYPE="xfs"
/dev/sr0: UUID="2019-03-21-13-42-32-00" LABEL="GParted-live" TYPE="iso9660" PTTYPE="dos"
Мы видим, что /boot и / нужные, размер 40GB, ОС работает. Счастье, не иначе!
Бонус
То, с чем придется столкнуться в некоторых ситуациях.
- Если VM на Windows, то вместо virt-sparsify можно использовать сжатие тома внутри ОС. Технически весь процесс одинаковый, однако известно, что метки тома меняются (мы это видели ранее в blkid), а значит Windows надо знать, что есть что в новой реальности. Для этого загружаемся в режим восстановления (после всех операций) и делаем fixmbr + rebuildbcd. Что именно и как — да поможет вам man
- Великая проблема — с xfs напороться на Superblock has unknown read-only compatible features (0x4) enabled. После загрузки ОС она будет работать в режиме read-only, а всё будет смонтировано как надо. Решение до безумия простое:
Скорее всего, когда всё делалось в gparted или ином окружении, версия ядра этого окружения была слишком новой, в котором xfs немного изменен, а именно отличаются метаданные и их версия. В результате xfs сделанный в новом ядре, превращается в тыкву на старом. Что делаем — загружаемся обратно в rescue gparted, поднимаем в этом rescue окружении сеть и ставим максимально свежее ядро в ОС. Я ставил 5.х на CentOS 7, возможно подойдет и 4.х, не проверял, но в итоге всё работало. Причем, без особых проблем.
На этом всё!
Как видите, ничего сложного в этом нет. Конечно, можно использовать LVM, resize2fs и прочие штуки, но всё-таки qcow2 где-то ещё используется и кому-то даже нужен.
Если вы знаете способ ещё более простой — напишите о нём в комментариях.