
Привет! Меня зовут Ваня, я системный администратор в Selectel. Даже если вы не планируете в ближайшее время клонировать сервер или мигрировать на другую инфраструктуру, лучше разобраться в этих вопросах заранее. Причин может быть много: смена провайдера, перенос проекта с облака на выделенный сервер, резервное копирование всей системы без даунтайма или развертывание тестовой среды, максимально приближенной к продакшену.
По катом расскажу, как перенести сервер с помощью снапшота и прямой передачи данных по сети — без создания образов и остановки сервисов. Метод подойдет и для облака, и для выделенных серверов.
Используйте навигацию, если не хотите читать текст целиком:
→ В чем суть метода
→ Почему не образ
→ Что такое снапшот и зачем он нужен
→ Подготовка принимающего сервера
→ Переносим сервер
В чем суть метода
Способ, о котором пойдет речь, основан на технологии CoW (Сopy-on-Write) — она позволяет записывать все изменения в копию объекта и при этом не изменять оригинал. Механизм можно реализовать как на уровне блочного устройства — например, LVM, так и на уровне файловой системы — например, btrfs и zfs.
Далее разберем именно вариант с файловой системой (ФС) — наиболее гибкий и удобный. Рассмотрим процесс переноса.
- Создаем снапшот текущей ФС.
- Переносим ФС по сети.
- Готовим загрузку на принимающей машине: пересобираем при необходимости ядро и initramfs, устанавливаем загрузчик (grub, systemd-boot или efi-stub).
- Проверяем, что все работает, и удаляем временные снапшоты.

Почему не образ
К этому моменту вы могли задаться логичным вопросом: зачем все это, если в облаке можно просто создать образ и развернуть новый сервер? Рассмотрим несколько ключевых преимуществ подхода.
Более универсальный. С помощью образа нельзя «просто так» переехать на выделенный сервер.
Не требует остановки сервиса. Снапшот создается на «живой» системе, а перенос идет в фоне. Приложения продолжают работать.
Быстрее. Образ — это, по сути, длинная цепочка операций между компонентами OpenStack. При этом большой локальный диск может «ехать» часами, а иногда — сутками. Передача снапшота по сети — это прямой потоковый процесс без промежуточных копий.

Пример копирования данных между компонентами OpenStack.
Что такое снапшот и зачем он нужен
Снапшот — это состояние файловой системы, зафиксированное в определенный момент времени. Он работает как точка восстановления и позволяет сохранить «слепок» всей структуры данных без копирования каждого файла.
Представим: в вашей файловой системе есть три файла —
1.txt
, 2.conf
и 3.png
. Вы создаете снапшот, однако пока он ничего не весит, ведь сохраненное состояние идентично настоящему — пока файлы не меняются, снапшот остается «незаполненным».После создания снапшота вы пошли дальше и изменили
2.conf
. Теперь у вас есть две версии файла: сохраненная в снапшоте и настоящая. Это произошло из-за того, что запись выполнялась в копию файла. Снапшот же теперь занимает ровно столько места, сколько весят внесенные обновления в 2.conf
, так как неизмененные части файла и так есть в настоящей версии.Идем дальше: вы удалили
3.png
, после чего он пропал из файловой системы. Однако он остался в снапшоте, который прибавил вес 3.png
.TL;DR: создав снапшот вы зафиксировали состояние ФС, но при этом не нарушили работу приложений, которые ее изменяют. Полученный снапшот можно скопировать на другой сервер, не рискуя целостностью данных.
Рассмотрим команды, которые вам пригодятся для создания снапшота.
Для btrfs:
btrfs subvolume snapshot -r / /mnt/rootfs-transfer
Для ZFS:
zfs snapshot zpool/rootfs@transfer
Подготовка принимающего сервера
Прежде чем приступить к переносу, важно подготовить принимающий сервер:
- Разметьте диск;
- Создайте файловую систему;
- Учтите нюансы загрузки (BIOS или UEFI);
- Если это выделенный сервер — продумайте использование RAID (raid1, raid5 и т. д., будет ли он реализован аппаратно, средствами ФС или с помощью mdadm);
- Загрузите сервер с livecd, например system-rescue.org.
Приведем примеры разметки.
BIOS-загрузка:
nvme0n1 476.9G disk
├─nvme0n1p1 1M part
├─nvme0n1p2 3G part /boot
└─nvme0n1p3 473.8G part
UEFI-загрузка:
nvme0n1 476.9G disk
├─nvme0n1p1 127M part /boot/efi
├─nvme0n1p2 3G part /boot
└─nvme0n1p3 473.8G part
В BIOS первый раздел нужен для установки
GRUB
— он должен обладать флагами bios_grub
и boot
. В UEFI это, наоборот, обычный раздел FAT32 с флагом esp
.Во втором разделе будут лежать ядро и
initramfs
. Строго говоря, он не нужен, если ваш загрузчик умеет читать btrfs
или zfs
, но я его все равно оставил — на всякий случай. 🙂 Оставшееся место отдадим под будущую ФС.ZFS:
zpool create -o ashift=12 -o autotrim=on -O normalization=formD -O acltype=posixacl -O xattr=sa -O dnodesize=auto -O canmount=off -O mountpoint=none zpool /dev/nvme0n1p3
Btrfs:
mkfs.btrfs /dev/nvme0n1p3
mount /dev/nvme0n1p3 /mnt
Переносим сервер
Обе ФС (
btrfs
, и zfs
) могут дампить снапшот в stdout
и принимать его через stdin
. Это позволяет передавать данные напрямую — просто через pipe, используя netcat
или ssh
. Без создания временного образа и без лишнего копирования. Далее в примере рассмотрим самый распространенный стек: GRUB и initramfs-tools, которые используют Debian и Ubuntu. Подробности о настройке загрузки вашего дистрибутива рекомендуем уточнять в его официальной документации.ZFS:
zfs send zpool/rootfs@transfer | ssh root@new-server zfs receive -F zpool/rootfs
Btrfs:
btrfs send /mnt/snapshots/rootfs-transfer | ssh root@new-server btrfs receive /mnt/rootfs-transfered
🎉 Данные перенесены! Если
/boot
был на отдельном разделе, его можно легко перенести с помощью rsync
, либо пересобрать все вручную:# перенос
rsync -aPvh /boot root@new-server:/boot
# пересборка внутри chroot:
apt reinstall linux-image-generic; update-initramfs -u -k all
Теперь давайте научим перенесенную систему загружаться: установим загрузчик, укажем изменившиеся данные в fstab и конфиге загрузчика. Все эти действия выполняем уже на новом сервере.
Если используем btrfs:
btrfs subvolume snapshot /mnt/rootfs-transfered /mnt/rootfs
umount /mnt
mount -o subvol=rootfs /dev/sdXX /mnt
arch-chroot /mnt
# смотрим новый UUID
blkid /dev/sdXX
# Здесь исправляем UUID и опцию subvolume, если выбрали имя отличное от того, что было. Если subvolume ранее не использовался, то самое время это исправить! Просто после defaults добавьте “,subvol=rootfs”
nano /etc/fstab
grub-install /dev/sdX
update-grub
Если используем ZFS:
zfs set canmount=noauto zpool/rootfs
zfs set mountpoint=/ zpool/rootfs
mount -t zfs -o zfsutil zpool/rootfs /mnt
# если /boot находится отдельно, монтируем его тоже:
mount /dev/sdY /mnt/boot
arch-chroot /mnt
grub-install /dev/sdX
update-grub
exit
# не забудьте отмонтировать /boot, если он был отдельно:
umount /mnt/boot
umount /mnt
zfs destroy zpool/rootfs@transfer
zpool export zpool
Обычно это не нужно, но если у вас в initramfs есть процессы, обращающиеся к реальной ФС, то перегенерируйте ее:
update-initramfs -u -k all
Теперь сервер готов к работе. Если снапшот больше не нужен — удалите его, чтобы он не продолжал постепенно занимать место (в зависимости от того, сколько изменений накопится после создания).
btrfs subvolume delete /mnt/snapshots/rootfs-transfer
zfs destroy zpool/rootfs@transfer