Приветствую,

Ну как вы поняли из заголовка этой заметки, сегодня рассмотрим варианты создания бекапов виртульных машин с KVM хостов.

В зависимости от критичности и загружености виртулки, мы можем применить способы:

  • С полным выключением виртуальной машины. В этом случаи все достаточно просто, мы копируем файл конфигурации виртуальной машины, и бекапим ее диск.
  • И когда виртуальная машина должна ранниться. Здесь же мы просто делаем снепшот виртуалки, и архивируем его.

Итак, у меня заготовлен kvm-хост c запущенной на нем виртуалкой.

[root@node3 ~]# virsh list
--
 Id    Name                           State
----------------------------------------------------
 40    testvm                         running

Бекап, с выключением VM

На виртуалку, я предварительно поставить и запустил nginx + mariadb. Что бы был какой то приближенный к реальности случай. kvm-vm-backup-ngx1.png

Итак, для выключаем виртуалку:

[root@node3 ~]# virsh shutdown testvm
Domain testvm is being shutdown

Что бы определить диск этой виртуальной машины, воспользуемся командой:

[root@node3 ~]# virsh domblklist testvm
---
Target     Source
------------------------------------------------
vda        /vm/testvm

Как вывод, диск виртульной машины лежит тут: /vm/testvm

Проверяем диск.

[root@node3 ~]# file /vm/testvm 
/vm/testvm: QEMU QCOW Image (v2), 20971520000 bytes

Копируем диск виртуальной машины в отдельный отведенный каталог:

[root@node3 ~]# cp -v /vm/testvm /mnt/vm_backups/
[root@node3 ~]# ls -lah /mnt/vm_backups/
---
-rw-------  1 root root 1.9G Jun 22 14:56 testvm

Далее делаем дамп конфигурации самой виртуалки:

[root@node3 ~]# virsh dumpxml testvm > /mnt/vm_backups/testvm.xml

Восстановление VM, из холодного бекапа

Теперь попробуем восстановить виртуалку, рядом с ее оригинальной копией. Для этого изменим некоторые параметры конфигурации vm в резервном xml-файле:

[root@node3 ~]# vim /mnt/vm_backups/testvm.xml
---
<domain type='kvm'>
  <name>testvm_restore</name>
  ....
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      ...
      <source file='/vm/testvm_restore'/>
      ...
    </disk>
    ....
  </devices>
</domain>

Открываем через редактор xml-конфиг, меняем поле <name>testvm_restore</name>. Далее спускаемся ниже в контекст devices, и в поле <source file='/vm/testvm_restore'/> указываем новый путь к диску виртуальной машины.

UDP: В этом же конфиге нужно удалить поле <uuid>ac85f69f.....</uuid>, иначе при восстановлении хост ругнется на уже существующий объект с этом uuid.

Сохраняемся и выходим.

Диск виртуальной машины копируем в исходный каталог:

[root@node3 ~]# cp -v /mnt/vm_backups/testvm /vm/testvm_restore
‘/mnt/vm_backups/testvm’ -> ‘/vm/testvm_restore’

Теперь остается создать новую виртуальную машину из нашего модифицированного xml-конфига:

[root@node3 ~]# virsh create /mnt/vm_backups/testvm.xml 
Domain testvm_restore created from /mnt/vm_backups/testvm.xml

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

К концу запускаем виртуальную машину, и проверяем работают ли там сервисы:

[root@node3 ~]# virsh list --all | grep testvm
 41    testvm_restore                 running
 -     testvm                         shut off

Nginx ранниться, можно считать эту задачу успешной.

[root@testvm_restore ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2023-06-22 15:19:45 +06; 4min 28s ago
  Process: 842 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 824 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 817 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 850 (nginx)
   CGroup: /system.slice/nginx.service
           ├─850 nginx: master process /usr/sbin/nginx
           ├─854 nginx: worker process
           ├─855 nginx: worker process
           └─856 nginx: worker process

Бекап без выключения VM

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

Для реализации бекапа так скажем на лету, на гостевую виртуальную машину нужно установить агента. Это некий софт который принимает запросы от хоста через virtio интерфейс и выполняет их.

Настройка qemu-guest-agent

Итак, перед созданием снепшота требуется немного перенастроить виртуальную машину.

На целевую виртульную машину ставим пакет - qemu-guest-agent. Поэтому подключаемся по ssh к виртуалке и ставим пакет:

[root@testvm_hot ~]# yum install qemu-guest-agent

И пробуем запустить агента:

[root@testvm_hot ~]# systemctl start qemu-guest-agent

Если в качестве гипервизора у вас используется proxmox, то скорее всего агент запустится. В моей же случаи используется чистый KVM, и что бы запустить гостевой агент нужно в конфигурации виртуальной машины добавить выше упомянутый virtio интерфейс, иначе агент будет отваливаться с ошибкой:

Job dev-virtio\x2dports-org.qemu.guest_agent.0.device/start timed out.
Timed out waiting for device dev-virtio\x2dports-org.qemu.guest_agent.0.device.

Для добавления нового устройства на в конфигурации vm, подключаемся к хосту. И редактируем конфигу виртуальной машины:

[root@node3 ~]# virsh edit testvm_hot
---
<devices>
    ....
    <channel type='unix'>
        <target type='virtio' name='org.qemu.guest_agent.0'/>
    </channel>
</devices>

В контексте devices, в самом конце добавляем строки:

<channel type='unix'>
    <target type='virtio' name='org.qemu.guest_agent.0'/>
</channel>

Сохраняемся и выходим.

Первый подводный камень который нас втречает, чтобы интерфейс повесился на виртуалку нам требуется выключить ее. И через несколько секунд включить сново. Да именно выключить, когда я тестировал, просто пробовал перезапустить vm. Но это не помогло.

Выключаем виртуалку, и запускаем вновь:

[root@node3 ~]# virsh shutdown testvm_hot
Domain testvm_hot is being shutdown

[root@node3 ~]# virsh start testvm_hot
Domain testvm_hot started

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

[root@testvm_hot ~]# systemctl status qemu-guest-agent
● qemu-guest-agent.service - QEMU Guest Agent
   Loaded: loaded (/usr/lib/systemd/system/qemu-guest-agent.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2023-06-22 21:40:39 +06; 1min 3s ago
 Main PID: 478 (qemu-ga)
   CGroup: /system.slice/qemu-guest-agent.service
           └─478 /usr/bin/qemu-ga --method=virtio-serial --path=/dev/virtio-ports/org.qemu.guest_agent.0

Отлично все ранится.

Ну и за одно проверяем доступен ли интерфейст со стороны хоста, командой:

[root@node3 ~]# virsh qemu-agent-command testvm_hot '{"execute":"guest-info"}'

Должна вернутся большая портянка в json-е.

Переходим к созданию бекапа. Сам по себе процесс прост. Мы сначала создаем моментальный снимок (снепшот) нашей виртуалки. После создания, запускаем архивирование диска куда-нибудь на выделенный бекапный каталог. И в конце выполняем консолидацию диска со снешотом.

Создание снепшота

Для запуска создания снепшоты выполним команду:

[root@node3 ~]# virsh snapshot-create-as --domain testvm_hot snaphot --disk-only --atomic --quiesce --no-metadata

Далее запускаем копирование или архивирование диска:

[root@node3 ~]# gzip -c /vm/testvm_hot > /mnt/vm_backups/testvm-hot.qz

Завершающим этапом выполняем слияние диска со снепшотом. Для получения дисков виртуальной машины запускаем команду:

[root@node3 ~]# virsh domblklist testvm_hot
---
Target     Source
------------------------------------------------
vda        /vm/testvm_hot.snaphot

Как видно из вывода целевое устройство - vda.

Ну и запускаем мерджинг:

[root@node3 ~]# virsh blockcommit testvm_hot vda --active --verbose --pivot
Block commit: [100 %]
Successfully pivoted

Если повторно выполним листинг блочный устройств, то в источник уже будет диск виртуальной машины. Не снепшот, как это было в прошлом.

[root@node3 ~]# virsh domblklist testvm_hot
Target     Source
------------------------------------------------
vda        /vm/testvm_hot

Проверяем работоспособность виртуальной машины, и удаляем старый снепшот:

[root@node3 ~]# rm -rf /vm/testvm_hot.snaphot 

По мимо бекапа диска виртуалки, не забываем сделать дамп ее конфигурации. Делается это таким же способом, что и в первом примере.

[root@node3 ~]# virsh dumpxml testvm_hot > /mnt/vm_backups/testvm_hot.xml

Восстановление VM, из live бекапа

Ранее созданный архив бекапа, распаковываем:

[root@node3 ~]# zcat /mnt/vm_backups/testvm-hot.qz >> /mnt/vm_backups/testvm-hot

По аналогии с прошлым методом редактируем конфиг виртуальной машины. Меняем имя в поле <name>, удаляем uuid. В контексте devices меняем путь к диску, прописываем путь к новому qcow2 файлу, поле <source file>.

[root@node3 vm_backups]# cat /mnt/vm_backups/testvm_hot.xml 
<domain type='kvm' id='45'>
  <name>testvm_hot-restore</name>
  ....
  <devices>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' io='threads'/>
      <source file='/vm/testvm-hot-restore'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <boot order='1'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    .....
  </devices>
</domain>

Ну и запускаем виртуалку.

[root@node3 vm_backups]# virsh create /mnt/vm_backups/testvm_hot.xml 

Отлично, теперь мы научились создавать бекапы в KVM =)