Restic: backup для современного мира
Restic - это простой, надежный, быстрый и эффективный способ резервного копирования. Простой в установке и настройке, с поддержкой большого количества бэкендов хранения, надежным шифрованием и дедупликацией. Это прекрасный инструмент для резервного копирования в современном ИТ-ландшафте. Тут я расскажу, зачем он нужен, как его поставить и начать им пользоваться.
Теоретическая часть
Предыстория
Исторически сложилось, что системы резервного копирования устроены очень сложно. Их сложно устанавливать, настраивать и сопровождать. Руководство к Veritas NetBackup (в дальнейшем - Symantec) имеет размеры приличной книги, по этой системе можно сдать экзамен и получить сертификат. Конфиг Amanda или Bacula весит под сотню килобайт, а официальное руководство занимает больше 500 страниц. Разумеется - у этой поражающей сложности есть простая, понятная, логичная причина, даже две:
- ненадежность медиа
- сложность процедуры бэкапа
Ненадежные медиа
Резервные копии надо где-то хранить. Традиционно используются цифровые кассеты (DAT/DLT), CD (в дальнейшем - DVD и BD) ROM/RW и жесткие диски. Проблема физических медиа в их не абсолютной надежности: кассеты размагничиваются и осыпаются, диски - царапаются и страдают от деградаций красочного слоя, про жесткие диски и говорить нечего. Из-за этого “классические” системы резервного копирования имеют сложные структуры расписаний и управление медиа-пулом. Медианосители надо постоянно перетасовывать, чтобы нагрузка на чтение и запись была равномерной и чтобы не оказалось, что весь огромный многотеррабайтный бэкап зависит от одного-единственного диска, который только что рассыпался в дисководе. Сложное расписание умножается на сложную структуру бэкапов (полный, инкрементальный, дифференциальный) где каждый слой зависит от другого. Это делается для экономия места и времени бэкапа. Кроме этого медиа ограничены в размере, а потому - нужно иметь возможность точно отфильтровать файлы и писать только то, что реально необходимо.
Сложная процедура бэкапа
В классическом традиционном ИТ-подходе бэкап - это очень сложная процедура. Бэкапим мы файлы, но данные нельзя воспринимать как файлы - они меняются. Бэкап файлов “в лоб” провоцирует инконсистентные данные, когда что-то поменялось на ходу и часть файлов находится в состоянии “до”, а часть - уже “после”. В том же Veritas NetBackup львиную долю цены лицензий состовляла цена агентов - сущностей, которые помогали бэкапить конкретные базы (Oracle, MSSQL) или состояния конкретных продуктов (SAP, BAAN). Агент знал, как “заморозить” состояние системы и получить консистентный бэкап, без него резервное копирование превращалось в лотерею. В opensource решениях агентов обычно нет, но родовые травмы в виде PreTask/PostTask остались - нужно подготовить данные к резервному копированию, а потом - вывести систему из этого состояния.
Restic: новый подход
Restic задуман как резервное копирование для современного ИТ-мира. Он имеет простой (предельно простой) интерфейс и минимум настроек. Одно из главных нововведений Restic - отказ от сложных медиа-операций. В современном ИТ в качестве системы хранения используется внешний сервис хранения, доступный обычно по S3 (Amazon S3, Azure BlobStorage, DigitalOcean Spaces, Minio на собственном оборудовании) или через прослойку в виде rclone (dropbox, Yandex.Disk). Restic предполагает такой бэкенд небезопасным, но надежным. Разумеется, данные внутри Amazon S3 хранятся на медиа, и медиа эти ненадежны. Однако между пользователем и медиа - несколько слоев абстракции, которые защищают данные, следят за их целостностью и верификацией. RAID-контроллеры, Erasure Codes, репликация между серверами-стойками-датацентрами, media scrubbing, check-суммы блоков - технологий десятки, если не сотни. По словам Dropbox - 80% трафика внутри их датацентров составляет служебный трафик, верификация, репликация и проверки данных, и только 20% - это собственно пользовательские данные. Restic исходит из идеи, что данные во внешнем хранилище содержатся вполне надежно и шансы получить битый или потеряный блок - минимальны. Именно по этому в Restic нет разделения на типы бэкапов - полные, инкрементальные и дифференциальные. Вместо этого предложен механизм snapshot-тов. Это просто снимок состояния системы в момент времени.
Как хранятся данные
Так как restic предполагает, что медиа - небезопасно - все данные шифруются AES256-CTR. Ключ AES шифруется паролем. Содержимое файлов нарезается на блоки (blobs) переменной длины (от 512кб до 8Мб), при этом каждый blob имеет контрольную сумму (CDC). Блоки упаковываются в пачки (pack). Пачка хранит в себе содержимое файла с метаданными или дерево (то есть - хранит в себе ссылки на другие пачки - файлы). Разные пачки могут ссылаться на один и тот же blob, что позволяет значительно экономить место. На самом верху этой пирамиды восседает snapshot, который хранит метаданные о, собственно, бэкапе (кто, когда, где) и ссылку на пачку с деревом верхнего уровня. При этом разные snapshot-ы могут ссылаться на одни и те же пачки деревьев, а пачки деревьев - на одни и те же пачки файлов (если файлы не менялись). Restic имеет удобную команду restic cat blob <blobId>
, которая позволяет посмотреть в содержимое конкретного блоба и выяснить, что там лежит.
Практическая часть
Установка и инициализация repository
Restic написан на go и потому распространяется в виде единственно бинарного файла, который содержит все необходимое. В Debian и Ubuntu он есть в виде пакета, так что поставить можно традиционно:
apt-get install -y restic
Ну или просто скачать готовый binary отсюда.
После установки нужно инициализировать repo. При этом restic сгенерирует ключ для шифрования и создаст структуру каталогов для хранения blob-ов, паков и snapshot-ов. Тут нужно сделать небольшое отступление: в рамках одного repo можно хранить бэкапы разных каталогов и даже разных хостов. Структура repo restic-а позволяет это делать и бэкапы не будут пересекаться друг с другом (hostname и path бэкапа - обязательный атрибут snapshot-а, так что можно легко отфильтровать нужный). Блобы общие в рамках repo, по этому если три разных хоста хранят одинаковый файл - в repo он будет хранится в одном блобе, что позволит сэкономить место.
Инициализация выполняется командой init
# для локальной файловой системы:
restic init --repo /mnt/disk0/backup-repo
# для S3-совместимых серверов (Minio, CEPH ObjGateway)
export AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
export AWS_SECRET_ACCESS_KEY=<MY_SECRET_ACCESS_KEY>
restic init --repo s3:https://my.local.server/backup-repo
# для Amazon S3 (European bucket)
export AWS_ACCESS_KEY_ID=<MY_ACCESS_KEY>
export AWS_SECRET_ACCESS_KEY=<MY_SECRET_ACCESS_KEY>
restic init -o s3.region="eu-west-1" --repo s3://s3.eu-west-1.amazonaws.com/bucketName/backupRepo
Главное - не забыть пароль, про который спросит restic. Именно этим паролем шифруется ключ и если пароль посеять - шансов на распаковку будет примерно ноль.
Типовые операции
Бэкап
Бэкап - основная операция, которая выполняется (по-хорошему), чаще всего:
restic -r /mnt/disk0/backup-repo backup /home/projects
Не всегда нужны все файлы. Для таких случаев есть ключ --exclude-file
. В этот можно добавить как конкретные файлы и папки (путь должен быть относительным, от корня бэкапа), так и regexp. Для парсинга файла используется filepath.Glob, так что синтаксис в деталях можно посмотреть тут.
Пример файла:
# просто папки
tmp
out
# файлы по расширению
*.deb
*.rpm
*.pyc
*.pyo
# файлы по пути. К примеру /home/projects/a/b/c/temp /home/projects/a/temp /home/projects/temp
/home/projects/**/temp
Получение списка snapshot-ов (из которых можно восстанавливать):
restic -r /mnt/disk0/backup-repo snaphots
repository 365c035e opened successfully, password is correct
ID Time Host Tags Paths
----------------------------------------------------------------------
119a1eb2 2020-04-30 15:48:20 mynote mynote,work /home/projects
ee597f8e 2020-05-31 00:30:01 mynote mynote,work /home/projects
a43ffe6a 2020-06-07 22:12:33 mynote mynote,work /home/projects
1d70de01 2020-06-10 00:32:43 mynote mynote,work /home/projects
0c236089 2020-06-12 18:44:56 mynote mynote,work /home/projects
e557bc74 2020-06-15 23:53:01 mynote mynote,work /home/projects
b39cf3de 2020-06-17 23:07:33 mynote mynote,work /home/projects
677b00d2 2020-06-19 11:40:50 mynote mynote,work /home/projects
8b781249 2020-06-20 00:07:52 mynote mynote,work /home/projects
d7c588a3 2020-06-23 10:15:06 mynote mynote,work /home/projects
----------------------------------------------------------------------
Сравнение двух snapshot-ов (дельта):
restic -r /mnt/disk0/backup-repo diff 119a1eb2 ee597f8e
password is correct
comparing snapshot 119a1eb2 to ee597f8e:
C /home/projects/cmd_diff.go
+ /home/projects/foo
C /home/projects/restic
Files: 0 new, 0 removed, 2 changed
Dirs: 1 new, 0 removed
Others: 0 new, 0 removed
Data Blobs: 14 new, 15 removed
Tree Blobs: 2 new, 1 removed
Added: 16.403 MiB
Removed: 16.402 MiB
Просмотр списка файлов в snapshot-е
Так можно посмотреть все файлы, которые можно найти в snapshot-е
restic -r /mnt/disk0/backup-repo ls -l latest
snapshot d7c588a3 of [/home/projects] filtered by [] at 2020-06-23 10:15:06.972887989 +0300 MSK):
/home
/home/projects
/home/projects/.ICEauthority
/home/projects/.PyCharmCE2019.3
/home/projects/.PyCharmCE2019.3/config
/home/projects/.PyCharmCE2019.3/config/codestyles
/home/projects/.PyCharmCE2019.3/config/codestyles/Default.xml
/home/projects/.PyCharmCE2019.3/config/inspection
/home/projects/.PyCharmCE2019.3/config/inspection/Default.xml
/home/projects/.PyCharmCE2019.3/config/options
/home/projects/.PyCharmCE2019.3/config/options/colors.scheme.xml
/home/projects/.PyCharmCE2019.3/config/options/debugger.xml
[...]
А так можно найти определенный (если восстановить хочется не все, а только определенные файлы):
restic find "**/blog/**/*.md" --snapshot latest
repository 365c035e opened successfully, password is correct
Found matching entries in snapshot d7c588a3
/home/projects/blog/_drafts/2017-11-06-deadend.md
/home/projects/blog/_drafts/2018-02-06-newway.md
/home/projects/blog/_posts/2005-01-14-openssh-key-auth.md
[...]
Восстановление из бэкапа
Самый простой вариант - восстановить все файлы из определенного snapshot-а. Latest как ID snapshot-а автоматически преобразуется в последний доступный snapshot
restic -r /mnt/disk0/backup-repo restore latest --target=tmptest/
repository 365c035e opened successfully, password is correct
restoring <Snapshot d7c588a3 of [/home/projects] at 2020-06-23 10:15:06.972887989 +0300 MSK by logan@mynote> to tmptest/
Если восстанавливать хочется не все - есть ключ --include
:
restic -r /mnt/disk0/backup-repo restore latest --target=tmptest/ --include ".PyCharmCE2019.3"
В этом случае будет восстановлена только папка .PyCharmCE2019.3
со всем ее содержимым. Обратный фокус с ключом --exclude
сработает тоже.
Проверки snapshot-ов
Целосность данных критически важна. Если будет потерян blob - все snapshot-ы, которые ссылаются на него - станут невалидными и не смогут восстановится. Для этой цели есть команда check
:
restic -r /mnt/disk0/backup-repo check
using temporary cache in /tmp/restic-check-cache-830311414
repository 365c035e opened successfully, password is correct
created new cache in /tmp/restic-check-cache-830311414
create exclusive lock for repository
load indexes
check all packs
check snapshots, trees and blobs
no errors were found
Уборка в репозитории
Restic по умолчанию не имеет политик очистки (retention policy), а значит - репозиторий будет расти вечно, с каждым изменением файла. Чтобы этого избежать - репозиторий надо чистить. Это делается в два шага:
- команда
forget
удаляет ненужные snapshot-ы из репозитория. Однако она не трогает сами блобы, на которые ссылаются эти snapshot-ы - команда
prune
удаляет блобы, на которые никто не ссылается. Именно в этот момент происходит реальная чистка репозитория.
Пример использования:
restic -r /mnt/disk0/backup-repo forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12
restic -r /mnt/disk0/backup-repo prune
В этом примере мы храним 7 последних ежедневных snapshot-ов, 4 snapshot-а недельных (что покрывает месяц) и 12 месячных. Это позволит нам вытащить бэкап за весь последний год, причем за последнюю неделю он ежедневный, за месяц - еженедельный а дальше - помесячный. Почему keep-weekly в этом примере равен 5? Потому что последний из 7 keep-daily попадает на недельный (это первый по-недельный snapshot). Чтобы проверить, какие snapshot-ы будут удалены - можно вызвать forget
с ключом --dry-run
. Никакого удаления при этом не производится и можно по выводу команды понять, отрабатывает ли политика так, как задумано.
Авторы restic рекомендуют запускать check после prune, чтобы убедится, что не произошло повреждения данных.
Использование в скриптах
Restic прекрасно работает в скриптах, в нем нет интерактивных элементов. Пароль можно задать с помощью переменных окружающей среды:
- RESTIC_PASSWORD - пароль repo “как есть”, открытым текстом без шифрования
- RESTIC_PASSWORD_FILE - файл с паролем repo. Без шифрования. Учитывается только первая строка. Имеет более высокий приоритет, чем RESTIC_PASSWORD (если задан RESTIC_PASSWORD_FILE, RESTIC_PASSWORD не учитывается)
- RESTIC_PASSWORD_COMMAND - команда, выполнение которой вернет пароль. Задавать ее в виде субпроцесса
$(command)
не нужно. Хороший вариант, если вы используете для шифрования PGP или менеджер паролей (pass, gopass, 1password-cli). Наивысший приоритет
Заключение
Restic - простой, быстрый и при правильном применении - вполне надежный инструмент. Простота настройки снижает риск ошибок, а скорость работы - повышает шансы, что все будет забэкаплено вовремя и как надо. Я очень рекомендую этот инструмент, он показал себя простым, гибким, удобным и надежным. И помните - системные администраторы делятся на две группы: те, кто не делают бэкапы и те, кто уже делают бэкапы :)