Уменьшаем qcow2 образ в Libvirt KVM

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Вам когда-нибудь доводилось уменьшать размер qcow2 образа диска, используемого в виртуальных машинах KVM-QEMU? Как известно, процесс увеличения размера образа довольно прост и быстр, а как обстоят дела с уменьшением?

В данной статье я расскажу про ситуацию, когда нужно уменьшить qcow2 образ виртуальной машины KVM в максимально быстрые сроки.


Формат блочных устройств — qcow2
Но, тем не менее, эту схему можно проделать и с raw образами, достаточно сконвертировать его в qcow2. В общем-то, инструкция будет актуальна для всего, что конвертируется в qcow2.

Простой способ уменьшения диска на KVM заключается в следующих этапах:

  1. Сжатие блочного устройства qcow2 (диска VM)
  2. Создание диска меньшего размера
  3. Подключение gparted образа, старого и нового диска
  4. Подготовка к загрузке ОС
  5. Характеристики 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


Как это делать, я опущу из данной статьи, так как подразумевается что выполняющий всё это уже знает, как это происходит, но результатом будет следующее:

image

Запускаем VM и видим загрузочный экран GParted:

image

Выбираем первый пункт и следуем инструкциям на экране. Я обычно нажимаю enter до конца.

image

Увидев сам GParted, приступаем к действу. Быстренько проверяем какая у /dev/vda таблица разделов — msdos или gpt. Это важно:

image

Переключаемся на второй диск /dev/vdb и создадим таблицу разделов:

image
image

При создании таблицы выбираем тип msdos как мы узнали ранее.

Затем переключаемся обратно на /dev/vda и последовательно, с первых дисков начинаем копировать разделы переключаясь между vda и vdb:

image

Конечным результатом будет:

image

Нажимаем Apply и ждем завершения результата:

image

В результате:

image

Что уже похоже на правду. Но так как мы сделали некоторые манипуляции, которые приведут к изменению UUID дисков, мы потенциально не загрузимся в ОС. Почему? CentOS 7 использует в fstab UUID дисков, Grub2 использует UUID дисков, поэтому прыгаем в консоль и занимаемся черной магией.

Gparted работает изначально под пользователем, поэтому прыгаем под root командой sudo su — root:

image

Сделаем blkid чтобы убедится, что UUID разделов поменялся

image

Видно, что 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 не очень удобно, заменим его на привычное название устройства.

image

Заменяем строку с 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, ОС работает. Счастье, не иначе!

Бонус

То, с чем придется столкнуться в некоторых ситуациях.

  1. Если VM на Windows, то вместо virt-sparsify можно использовать сжатие тома внутри ОС. Технически весь процесс одинаковый, однако известно, что метки тома меняются (мы это видели ранее в blkid), а значит Windows надо знать, что есть что в новой реальности. Для этого загружаемся в режим восстановления (после всех операций) и делаем fixmbr + rebuildbcd. Что именно и как — да поможет вам man
  2. Великая проблема — с 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 где-то ещё используется и кому-то даже нужен.

Если вы знаете способ ещё более простой — напишите о нём в комментариях.
Источник: https://habr.com/ru/post/525922/


Интересные статьи

Интересные статьи

В одном из проектов возникла необходимость перевести процессы импорта данных сторонних систем на микросервисную архитектуру. В качестве инструмента выбран Apache NiFi. В качестве первого ...
Предыстория Когда-то у меня возникла необходимость проверять наличие неотправленных сообщений в «1С-Битрикс: Управление сайтом» (далее Битрикс) и получать уведомления об этом. Пробле...
Без бэкендеров не сможет нормально функционировать ни один сайт или приложение. Они проектируют алгоритмы взаимодействия сайта с пользователем и другими интернет-сервисами. Другим...
В современном понимании процесс обучения рассматривается как процесс взаимодействия между учителем и учениками с целью приобщения учащихся к определенным знаниям, навыкам, умениям...
Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.