Search
Write a publication
Pull to refresh

Инкрементальное и дифференциальное резервное копирование виртуальной машины QEMU/KVM

Level of difficultyMedium

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

Опишу этот алгоритм, как последовательность команд терминала.

Версии программ.

$ qemu-system-x86_64 --version

QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.42)

Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers

$ virsh --version

4.0.0

Процесс копирования.

  1. Запрашиваем состояние виртуальной машины (ВМ)

    $ virsh list

    Id Name State

    ----------------------------------------------------

    2 my_vm running

    ВМ работает (это важно).

  2. Запрашиваем список дисков ВМ

    $ virsh domblklist my_vm --details

    Type Device Target Source

    ------------------------------------------------

    file disk hda /var/lib/libvirt/images/my.img

  3. Создаем папку для копии:

    $ mkdir -p ~/backup/my_vm

  4. Меняем права доступа к ней (для предоставления прав QEMU )

    $ chmod 777 ~/backup/my_vm/

  5. В QEMU у дисков собственные имена, поэтому запрашиваем список блочных устройств:

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"query-block"}' | grep '"node-name":'

    "node-name": "#block189"

    Итак, наш диск в дальнейшем - "#block189"

  6. Создаем битовую карту измененных блоков "my_bitmap" для хранения информации об изменениях диска:

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"block-dirty-bitmap-add","arguments": {"node": "#block189", "name": "my_bitmap"}}'

    {

    "return": {

    },

    "id": "libvirt-30"

    }

  7. Операции по копированию QEMU будет проводить в фоновом режиме, для получения результата завершения запускаем второй терминал и выполняем в нем команду ожидания:

    $ virsh qemu-monitor-event --timeout 3600 --event BLOCK_JOB_COMPLETED

  8. Возвращаемся в первый терминал и запускаем процесс получения начальной полной копии диска ВМ

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"transaction","arguments": {"actions": [ {"type": "drive-backup","data": {"device": "#block189","target": "/home/piter/backup/my_vm/my_vm.inc.0","sync": "full","format": "qcow2","job-id":"JOB1"}}]}} '

    {

    "return": {

    },

    "id": "libvirt-34"

    }

  9. Периодически можем запрашивать состояние процесса в первом терминале:

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"query-block-jobs"}'

    {

    "return": [

    {

    "io-status": "ok",

    "device": "JOB1",

    "busy": true,

    "len": 4089446400,

    "offset": 3254517760,

    "paused": false,

    "speed": 0,

    "ready": false,

    "type": "backup"

    }

    ],

    "id": "libvirt-33"

    }

  10. Ожидаем завершения процесса копирования во втором терминале и получаем результат:

    event BLOCK_JOB_COMPLETED at 1752478453.041380 for domain my_vm: {"device":"JOB1","len":4089446400,"offset":4089446400,"speed":0,"type":"backup"}

    events received: 1

    Процесс завершен без ошибок.

  11. Копируем в папку xml файл описания ВМ

    $ virsh dumpxml my_vm > ~/backup/my_vm/libvirt.xml

  12. Создаем заготовку первого инкремента, как файла изменений для полного файла (inc.0):

    $ qemu-img create -f qcow2 /home/piter/backup/my_vm/my_vm.inc.1 -b /home/piter/backup/my_vm/my_vm.inc.0 -F qcow2

    Formatting '/home/piter/backup/my_vm/my_vm.inc.1', fmt=qcow2 size=4089446400 backing_file=/home/piter/backup/my_vm/my_vm.inc.0 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16

  13. Меняем на него права:

    $ chmod 666 ~/backup/my_vm/my_vm.inc.1

  14. Запускаем первое инкрементальное копирование:

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"transaction","arguments": {"actions": [ {"type": "drive-backup","data": {"device": "#block189","bitmap": "my_bitmap","target": "/home/piter/backup/my_vm/my_vm.inc.1","sync": "incremental","format": "qcow2","job-id":"JOB1","mode": "existing"}}]}} '

    {

    "return": {

    },

    "id": "libvirt-37"

    }

  15. Ожидание завершения операции - такое же. Аналогично создаем заготовку второго инкремента, как файла изменений для первого (inc.1):

    $ qemu-img create -f qcow2 /home/piter/backup/my_vm/my_vm.inc.2 -b /home/piter/backup/my_vm/my_vm.inc.1 -F qcow2

    Formatting '/home/piter/backup/my_vm/my_vm.inc.2', fmt=qcow2 size=4089446400 backing_file=/home/piter/backup/my_vm/my_vm.inc.1 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16

  16. Меняем на него права:

    $ chmod 666 ~/backup/my_vm/my_vm.inc.2

  17. Второе инкрементальное копирование:

    $ virsh qemu-monitor-command my_vm --pretty '{"execute":"transaction","arguments": {"actions": [ {"type": "drive-backup","data": {"device": "#block189","bitmap": "my_bitmap","target": "/home/piter/backup/my_vm/my_vm.inc.2","sync": "incremental","format": "qcow2","job-id":"JOB1","mode": "existing"}}]}} '

    {

    "return": {

    },

    "id": "libvirt-39"

    }

    Процесс копирования инкрементов может продолжаться и далее.

    Копия ВМ содержит xml файл описания и последовательный набор инкрементов:

    $ ls ~/backup/my_vm/

    libvirt.xml my_vm.inc.0 my_vm.inc.1 my_vm.inc.2

    Следует помнить, что останавливать ВМ нельзя, т. к. битовая карта измененных блоков будет утрачена.

    Процесс восстановления.

    Копия ВМ — это цепочка файлов изменения:

    $ qemu-img info ~/backup/my_vm/my_vm.inc.2 | grep 'backing file:'

    backing file: /home/piter/backup/my_vm/my_vm.inc.1

    $ qemu-img info ~/backup/my_vm/my_vm.inc.1 | grep 'backing file:'

    backing file: /home/piter/backup/my_vm/my_vm.inc.0

    Итак:

    1. Необходимо сохранить все файлы из папки ~/backup/my_vm/ , так как они изменятся в процессе последующих действий.

    2. Останавливаем ВМ

      $ virsh shutdown my_vm

    3. Восстанавливаем диск ВМ, последовательно присоединяя файлы изменений от самого последнего к нулевому:

      $ qemu-img commit ~/backup/my_vm/my_vm.inc.2

      Image committed.

      $ qemu-img commit ~/backup/my_vm/my_vm.inc.1

      Image committed.

      Процесс восстановления диска ВМ завершен. Копия восстановленного диска - в файле ~/backup/my_vm/my_vm.inc.0

    4. Копируем восстановленный диск. Напоминаем, что он в формате "qcow2", а my.img - "raw"

      $ qemu-img convert -f qcow2 ~/backup/my_vm/my_vm.inc.0 -O raw /var/lib/libvirt/images/my.img

      Процесс восстановления завершен.

    Дифференциальное резервное копирование

    В данном случае мы не держим всю цепочку изменений, а сохраняем только полную копию (inc.0) и суммарно накопленные изменения (inc.1).

    После получения инкремента inc.2 сразу же вносим изменения в дифференциальный файл (inc.1):

    $ qemu-img commit ~/backup/my_vm/my_vm.inc.2

    Image committed.

    $ rm ~/backup/my_vm/my_vm.inc.2

    Далее процесс периодически повторяется.

    При восстановлении из копии цепочка будет состоять всего из двух файлов, что ускорит процесс.

    Более углублено изучить данную тему можно по следующим ссылкам:

    Features/IncrementalBackup

    Dirty Bitmaps and Incremental Backup

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.