В чем разница между snapshot, backup и clone VPS
Узнайте ключевые отличия между снапшотами, бэкапами и клонами серверов. Поймите, почему снапшот не является резервной копией и какие настройки нужно менять после клонирования.
Что на самом деле представляют собой snapshot, backup и clone
Snapshot VPS — это образ диска вашего сервера, который хранится у провайдера, на его инфраструктуре и в рамках вашей учетной записи. Backup — это независимая копия ваших данных, которую можно восстановить в другом месте без участия провайдера, у которого хранились исходные данные. Clone — это новый экземпляр, развернутый из snapshot, поэтому он начинает работу как точная копия оригинала, включая идентификационные данные.
Они решают разные задачи. Snapshot позволяет за считанные минуты откатить неудачное обновление, но он бесполезен, если ваша учетная запись заблокирована. Backup сохраняет данные, даже если провайдер прекратит существование, однако восстановление занимает больше времени, так как сначала нужно развернуть машину. Clone позволяет получить второй работающий сервер за один шаг, но при этом у вас появляются две машины, которые считают себя одним и тем же устройством.
Почему снапшот VPS — это не резервная копия
Проблема заключается в домене отказа, а не в качестве образа. Снапшот хранится на платформе хранения вашего провайдера, обычно в том же регионе, что и сервер, и всегда в рамках одной учетной записи. Одно событие может уничтожить и сервер, и его снапшот.
- Учетная запись заблокирована, платеж не прошел или кто-то украл данные для входа.
- Человек или скрипт с доступом к API удаляет инстанс. У многих провайдеров удаление инстанса приводит к удалению связанных с ним снапшотов. Ознакомьтесь с документацией вашего провайдера, прежде чем полагаться на обратное.
- В регионе происходит сбой, из-за которого всё содержимое становится недоступным одновременно.
- Процесс, запущенный с правами root на сервере, находит API-токен провайдера, оставленный вами в
/root, и удаляет снапшоты до того, как затронет диск.
Резервная копия — это копия, которая переживет все четыре сценария. Проверка проста: если ваша учетная запись у провайдера перестанет существовать сегодня, что вы сможете восстановить и куда? Всё, что не проходит эту проверку, является лишь инструментом отката. Продолжайте делать снапшоты, так как ничто не восстанавливается быстрее. Но при этом храните вторую копию на носителе, который не контролируется вашим провайдером.
Старое правило остается в силе: три копии данных на двух типах носителей, одна из которых находится вне платформы. Снапшот провайдера плюс репозиторий резервных копий restic на отдельной инфраструктуре обеспечивают это решение с помощью двух независимых компонентов.
Почему снапшот работающей базы данных может привести к повреждению данных
Снапшот провайдера копирует блочное устройство в том виде, в котором оно находится в конкретный момент времени. Он не запрашивает предварительную остановку приложений и не видит данные, которые всё ещё находятся в страничном кэше. Поэтому такой образ в лучшем случае является crash-consistent (согласованным на момент сбоя). Он выглядит в точности так же, как выглядел бы диск, если бы кто-то выдернул кабель питания.
Большинство компонентов стека справляются с этим. ext4 и XFS воспроизводят свой журнал при монтировании, поэтому файловая система восстанавливается. PostgreSQL воспроизводит свой журнал предзаписи (write-ahead log) при запуске, о чём свидетельствует запись в логе:
LOG: database system was not properly shut down; automatic recovery in progressInnoDB делает то же самое и выводит собственные строки восстановления после сбоя во время запуска. Это восстановление является штатной работой базы данных, поэтому снапшот одного тома с неактивной PostgreSQL или MySQL обычно восстанавливается без проблем.
Случаи, когда crash-consistent недостаточно, реальны, и именно они приводят к проблемам. Если ваши данные распределены по двум томам, корневой диск и отдельный диск с данными будут запечатлены в разные моменты времени. В результате файлы данных и каталог логов могут оказаться несогласованными, и процессу восстановления будет нечего корректно воспроизвести. Любой файл, который приложение записывает без вызова fsync, например, частично полученная загрузка или файл очереди, может оказаться обрезанным. Всё, что приложение удерживает в памяти и сбрасывает на диск по таймеру, просто отсутствует в образе.
Поэтому перед созданием снапшота запишите дамп на диск. Тогда образ будет содержать один файл, который гарантированно является внутренне согласованным, независимо от состояния «живых» файлов данных.
sudo -u postgres pg_dumpall --clean --file=/var/backups/pg-$(date +%F).sql
sudo mysqldump --single-transaction --routines --all-databases > /var/backups/mysql-$(date +%F).sql--single-transaction позволяет получить согласованный дамп таблиц InnoDB без блокировки записи, так как дамп выполняется внутри одной транзакции repeatable-read. Это не распространяется на таблицы MyISAM, для которых требуется блокировка или остановка сервера. Перед тем как доверять дампу, убедитесь, что он не пуст и не обрезан: tail -n 1 /var/backups/mysql-$(date +%F).sql для полного mysqldump заканчивается комментарием Dump completed.
Если у вас есть отдельный том с данными, вы можете заморозить его на те несколько секунд, которые требуются для создания снапшота:
sudo fsfreeze -f /srv
# take the snapshot from your provider's panel or API
sudo fsfreeze -u /srvЗамораживайте только том с данными. Никогда не замораживайте /. Замороженная корневая файловая система блокирует любую запись на сервере, включая оболочку (shell), которую вы использовали бы для ввода команды разморозки. В итоге вы заблокируете сами себя и будете вынуждены выполнять аппаратную перезагрузку.
Внешняя копия: restic или Borg
Снимок — это быстрая часть процесса. Внешняя копия — это та часть, которая уцелеет при выходе из строя вашего провайдера. restic — хороший выбор по умолчанию, так как он выполняет дедупликацию, шифрование на стороне клиента и запись в S3-совместимое объектное хранилище, SFTP или обычную директорию. VPS для хранения данных в качестве удаленной цели здесь отлично подходит, так как для репозиториев резервных копий важнее объем, а не IOPS.
sudo apt update && sudo apt install -y restic
sudo sh -c 'umask 077; head -c 24 /dev/urandom | base64 > /root/.restic-pass'
sudo chmod 600 /root/.restic-pass
sudo cat /root/.restic-passСкопируйте эту кодовую фразу в менеджер паролей прямо сейчас, на устройство, отличное от этого сервера. Репозиторий restic невозможно открыть без неё, и пути восстановления не существует. Если единственная копия пароля была на сервере, который вы только что потеряли, резервная копия превращается в зашифрованный шум.
export RESTIC_REPOSITORY="s3:https://s3.example.com/vps-backups"
export RESTIC_PASSWORD_FILE=/root/.restic-pass
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
sudo -E restic init
sudo -E restic backup /etc /srv /var/backups
sudo -E restic snapshotssudo -E сохраняет эти переменные, так как без них root получает чистую среду, и restic сообщает, что расположение репозитория не указано. restic snapshots должен вывести только что выполненный запуск с указанием хоста и путей. Проверяйте сам репозиторий по расписанию и считывайте часть данных обратно, а не ограничивайтесь только проверкой структуры:
sudo -E restic check --read-data-subset=5%
sudo -E restic restore latest --target /tmp/restore-check
sudo -E restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneНепроверенная резервная копия — это лишь предположение. Выполните восстановление на другой VPS хотя бы один раз, замерьте время и запишите его, так как это число является вашим реальным целевым показателем восстановления. Borg — еще один надежный вариант, он хранит репозиторий через SSH, а не в объектном хранилище; различия между ними описаны в сравнении restic и BorgBackup.
Что нужно исправить перед вводом клонированного VPS в эксплуатацию
Клон — это точная копия. В этом его преимущество и одновременно главная проблема. Всё, что делало оригинал уникальным, дублируется, и эти дубликаты вступают в конфликт.
Пересоздайте SSH host keys. Клон содержит файлы /etc/ssh/ssh_host_* от оригинала, поэтому два сервера предъявляют одну и ту же идентификационную информацию. Любой, кто контролирует один сервер, может выдать себя за другой для любого клиента, который уже принял этот ключ. SSH не выдаст предупреждение, так как ключ совпадает с тем, который ожидал клиент.
sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart ssh
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubssh-keygen -A записывает свежий ключ каждого типа, который ожидает демон. Отпечаток (fingerprint) после выполнения последней команды должен отличаться от отпечатка оригинала. Ваша текущая сессия сохранится после перезапуска, так как перезагрузка sshd не разрывает установленные соединения. Выполните это до того, как кто-либо подключится к клону. Если отложить это на потом, каждый клиент, который уже доверял унаследованному ключу, получит WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! и будет вынужден сначала выполнить ssh-keygen -R <host>.
Сбросьте machine ID. /etc/machine-id — это уникальный идентификатор, который systemd генерирует один раз при первой загрузке, и клон наследует его.
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo rebootПустой файл /etc/machine-id указывает systemd сгенерировать новое значение при следующей загрузке, поэтому файл нужно очистить, а не удалять. При дублировании этого идентификатора возникают две проблемы. В образах, получающих адрес по DHCP, systemd-networkd по умолчанию выводит идентификатор DHCP-клиента из machine ID. В результате оба клона запрашивают аренду как один и тот же клиент, и сервер выдает им одинаковый адрес. Кроме того, journald помечает каждую запись этим идентификатором, поэтому централизованный сборщик логов записывает данные обоих серверов как от одной машины. Выполните cat /etc/machine-id после перезагрузки и убедитесь, что значение изменилось.
Измените hostname.
sudo hostnamectl set-hostname web-02
grep 127.0.1.1 /etc/hostshostnamectl записывает /etc/hostname и применяет имя немедленно. Команда не затрагивает /etc/hosts, поэтому отредактируйте строку 127.0.1.1, чтобы она соответствовала новому имени. Если этого не сделать, новое имя не будет разрешаться, и каждый вызов sudo будет ждать завершения неудачного поиска и выводить sudo: unable to resolve host web-02: Name or service not known.
Ротируйте все учетные данные, зашитые в образ. Клон содержит секреты оригинала, и теперь две машины могут действовать от имени оригинала. Проверьте файлы authorized_keys SSH, токены провайдеров и DNS API, файлы .env приложений, пароли баз данных, закрытые ключи TLS, токены регистрации в системах мониторинга и пароль репозитория restic. Эта команда поможет найти большинство из них:
sudo grep -rIlE 'PASSWORD|SECRET|TOKEN|API_KEY' /etc /srv /opt /home 2>/dev/null
sudo find / -name '.env' -not -path '/proc/*' -not -path '/sys/*' 2>/dev/nullЕсли клон — это тестовая копия, которая не будет обслуживать трафик, лучше отозвать доступы, чем ротировать их. Стейджинг-сервер с активным рабочим API-токеном — это тот же продакшн, но с худшим уровнем обновлений безопасности.
Отключите задания, которые теперь выполняются дважды. Два сервера с одинаковым crontab будут обращаться к одним и тем же внешним системам в одну и ту же минуту.
systemctl list-timers --all
sudo crontab -l
sudo ls -l /etc/cron.d /etc/cron.dailyСлучай с restic стоит разобрать отдельно, так как это приводит к повреждению политики хранения, а не просто к ошибкам. restic помечает каждый снапшот именем хоста, а restic forget --keep-daily 7 применяет политику для каждого хоста отдельно. Две машины с одинаковым именем хоста воспринимаются как один хост, поэтому семь «ежедневных» снапшотов могут быть созданы клоном, в то время как снапшоты оригинала будут удалены. Исправьте hostname до первого запуска резервного копирования или остановите таймер на клоне. С certbot всё проще: два сервера, обновляющие одни и те же имена, превысят лимит центра сертификации на количество дубликатов сертификатов. Проигравший процесс завершится с ошибкой о слишком большом количестве выпущенных сертификатов для данного набора имен. Клон, домен которого всё еще указывает на оригинал, в любом случае не сможет пройти HTTP-челлендж, поэтому отключите обновление сертификатов на нем.
Настройте агент мониторинга. Большинство агентов идентифицируются по hostname или файлу ID, созданному при установке. Два агента, сообщающие данные от одного хоста, смешивают метрики в одну серию. Графики CPU будут показывать значения, которые не производила ни одна отдельная машина, а алерты будут постоянно срабатывать. Остановите и удалите агент на клоне или перерегистрируйте его под новым hostname согласно документации вашего вендора.
Проверьте сетевую конфигурацию на наличие адреса оригинала. Если образ содержит статический адрес в netplan, клон займет IP-адрес, принадлежащий другой машине.
ip -br addr
sudo grep -r addresses /etc/netplan/Очистите состояние cloud-init, если этот клон станет шаблоном.
sudo cloud-init clean --logsЭто удалит состояние cloud-init в /var/lib/cloud, поэтому при следующей загрузке снова сработают модули первого запуска, включая генерацию SSH host keys, если они отсутствуют. Некоторые версии также предлагают флаг для сброса machine ID. Выполните cloud-init clean --help на своем образе, чтобы увидеть, что именно поддерживает ваша версия, вместо того чтобы полагаться на список флагов из других источников.
Когда и что использовать
Откат рискованного обновления: создание снимка (snapshot). Сделайте снимок за несколько минут до внесения изменений, выполните обновление и восстановите образ, если что-то пойдет не так. Восстановление отменяет все записи, сделанные после создания снимка, поэтому, если сервер обрабатывает реальный трафик, сначала выгрузите базу данных и точно определите, какой объем данных будет потерян. Для do-release-upgrade на сервере, который можно отключить от сети на десять минут, снимок является исчерпывающим планом действий.
Миграция на более мощный тариф: развертывание клона. Создайте клон из снимка на сервере с более мощным тарифом, выполните все пункты из списка идентификации выше, а затем протестируйте его на собственном IP-адресе до переключения трафика. За день до этого уменьшите значение TTL в DNS, чтобы переключение прошло быстро, и оставьте исходный сервер работающим, пока новый не выдержит нагрузку реальным трафиком. Сначала убедитесь, что более мощный тариф действительно ускоряет вашу рабочую нагрузку, используя один и тот же метод тестирования производительности на обоих серверах, так как большее количество vCPU на более загруженном оборудовании не всегда означает повышение производительности.
Создание шаблона: снимок очищенной системы. Установите и защитите один сервер, затем удалите все уникальные данные перед созданием образа. Никаких ключей хоста, пустой machine ID, никаких личных authorized_keys, никаких учетных данных, очищенный cloud-init. Сделайте снимок. Каждый экземпляр, развернутый из такого шаблона, при первой загрузке генерирует собственную идентификацию, поэтому приведенный выше контрольный список перестает быть нужным. Совместите это с стандартными первыми десятью минутами на новом VPS, чтобы шаблон уже содержал всю работу, которую в противном случае пришлось бы повторять.
FAQ
Является ли снапшот VPS резервной копией?
Нет, так как он разделяет домен отказа с сервером, на котором был создан. Снапшот хранится в инфраструктуре вашего провайдера, в вашей учетной записи и, как правило, в том же регионе. Блокировка аккаунта, кража API key или случайное удаление инстанса могут привести к потере сервера и всех его снапшотов одновременно. У многих провайдеров удаление инстанса автоматически удаляет и его снапшоты. Снапшот — это самый быстрый способ отката, поэтому делайте их регулярно, но обязательно храните вторую зашифрованную копию на инфраструктуре, которую не контролирует ваш провайдер.
Нужно ли останавливать базу данных перед созданием снапшота?
Не всегда, но вы должны понимать последствия. Снапшот провайдера обеспечивает crash-consistency: образ диска будет выглядеть так, как будто произошло внезапное отключение питания. PostgreSQL и InnoDB восстанавливаются после этого при запуске, при этом PostgreSQL записывает в лог database system was not properly shut down; automatic recovery in progress. Восстановление не гарантировано, если данные распределены по двум томам, снапшоты которых были сделаны в разное время, или если приложение записывает данные без fsync. Сначала выполните pg_dumpall или mysqldump --single-transaction, чтобы на диске гарантированно оказался один файл в консистентном состоянии.
Почему два клонированных сервера конфликтуют из-за одного IP-адреса?
Потому что они используют одинаковый /etc/machine-id. В образах, использующих DHCP, systemd-networkd по умолчанию формирует идентификатор DHCP-клиента на основе machine ID. В результате оба клона запрашивают аренду как один и тот же клиент, и DHCP-сервер выдает им одинаковый адрес. Обнулите файл /etc/machine-id, удалите /var/lib/dbus/machine-id, создайте символическую ссылку на /etc/machine-id и перезагрузитесь, чтобы systemd сгенерировал новое значение. Другая частая причина — статический адрес, прописанный в /etc/netplan/, который был скопирован в клон без изменений; проверьте это с помощью ip -br addr.
Как быстрее всего проверить, готов ли клон к работе в production?
Сравните четыре параметра с оригиналом. Выполните ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub на обоих и убедитесь, что отпечатки ключей различаются. Выполните cat /etc/machine-id на обоих и убедитесь, что значения различаются. Выполните hostnamectl status и убедитесь, что имя хоста новое и корректно разрешается, чтобы sudo не выдавал предупреждений. Затем выполните systemctl list-timers --all и остановите все таймеры, которые взаимодействуют с общими системами (например, резервное копирование, обновление сертификатов или агент мониторинга), пока не определите, какая машина будет отвечать за эти задачи.