← Заметки

Бэкап OpenWrt-хостов и их виртуалок в Proxmox Backup Server

· openwrt, proxmox, backup, qemu, ucode

Часть моих коробок на OpenWrt — x86-машины, на которых под голым QEMU крутится ещё одна-две виртуалки. Всё остальное в хоумлабе бэкапится в Proxmox Backup Server, значит, и они должны. Этим занимаются два пакета из моего фида для OpenWrt.

Клиент

Для бэкапов в PBS нужен proxmox-backup-client, а он на Rust, и в OpenWrt его нет. Пакет proxmox-backup в фиде собирает из исходников upstream только клиент, с несколькими патчами: сборка cargo только клиента, без libsystemd и с системным zstd. Пока я проверял его только на x86_64.

pbs-helper: бэкап самого хоста

pbs-helper добавляет pbs-backup, который бэкапит корневую файловую систему роутера как архив .pxar. Настройка — через UCI:

# /etc/config/pbs
config proxmox_backup_server 'pbs_server'
	option enabled '1'
	option repository 'backup@pbs@pbs.example.org:datastore'
	option password '...'
	option backup_name 'rootfs'
	option prefix '/'
	list backup_arg '--exclude=/tmp'
	option hc_ping_url 'https://hc-ping.com/<uuid>'
	option gotify_url 'https://gotify.example.org'
	option gotify_app_token '...'

и строчка в cron вроде 0 1 * * * /usr/bin/pbs-backup.

Несколько деталей, которые мне важны:

За ним стоит pbs.helper — небольшой ucode-модуль, который запускает задачи и общий с бэкапами виртуалок ниже. Все побочные эффекты — запуск команд, HTTP, логирование — внедряются снаружи, так что он покрыт юнит-тестами без всякого роутера.

qemu-instance-init: виртуалки как сервисы

qemu-instance-init вырос из init-скрипта из вики OpenWrt, переписанного под procd. Каждая VM — секция UCI:

# /etc/config/qemu
config instance 'vm1'
	option vcpus '2'
	option ram '2G'
	option root_disk '/dev/vg0/vm1'
	option root_disk_type 'lvm'
	option net0_mac '52:54:00:12:34:56'
	option net0_bridge 'br-lan'
	option guest_agent '1'
	option backup '1'
	option backup_server 'pbs_server'

procd запускает гостей и перезапускает при падении. При остановке скрипт отправляет ACPI system_powerdown через QMP и даёт гостю время спокойно выключиться, прежде чем procd его убьёт. UEFI-гости работают с OVMF, а сокет гостевого агента включается одной опцией.

Пакет есть в двух вариантах. qemu-instance-init — только init-скрипт. qemu-instance-init-pbs добавляет /etc/init.d/qemu backup [instance], который работает через тот же pbs.helper с теми же отчётами в Healthchecks и Gotify.

Консистентные бэкапы работающих VM

Если читать диск работающей виртуалки, получится бэкап диска, который менялся, пока его читали. Вариант -pbs держит его неподвижным:

  1. Заморозить файловые системы гостя через гостевой агент: гость сбрасывает кэши и перестаёт писать.
  2. Снять снапшот диска:
    • для дисков на LVM — lvcreate -s. kmod-dm в OpenWrt собран без поддержки снапшотов, поэтому в фиде есть небольшой пакет kmod-dm-snapshot;
    • для qcow2 — временный overlay через QMP blockdev-snapshot-sync: запись гостя идёт в overlay, а базовый файл перестаёт меняться.
  3. Разморозить сразу же — гость заморожен только на время снапшота.
  4. Забэкапить снапшот или базовый файл.
  5. Прибраться: удалить LVM-снапшот или влить overlay обратно через block-commit и удалить его.

Если чего-то не хватает, бэкап не падает, а деградирует с предупреждением в отчёте: без гостевого агента получится снапшот, консистентный как после внезапного отключения питания, без снапшота — сброс кэшей и потом живой диск. Остатки тоже подбираются: устаревший LVM-снапшот удаляет следующий бэкап, а overlay, брошенный убитым бэкапом, вливается обратно следующим бэкапом или, если VM была остановлена, при следующем старте.