Duplicacy на сервере: частые ошибки и решения
Duplicacy устроен иначе, чем большинство бэкап-утилит: он умеет дедуплицировать данные с нескольких машин на одном хранилище без центрального сервера-координатора, используя блокировку не файлов, а отдельных chunks. Это удобно, но именно эта особенность — источник половины непонятных ошибок: путаница с snapshot-id, «зависшие» fossils после prune, неожиданно исчезающие chunks при восстановлении. Разберём частые проблемы Duplicacy на сервере по симптому, причине и решению — с командами.
Содержание
- Инициализация хранилища и пароль шифрования
- Несколько клиентов на одном хранилище: snapshot-id и chunk-уровень
- Локальное или SFTP-хранилище: права и путь
- Фильтры .duplicacy/filters: бэкапится не то
- prune и fossil collection: как правильно чистить старые ревизии
- Восстановление: chunk not found и выбор ревизии
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Инициализация хранилища и пароль шифрования
Первая заминка обычно случается на команде init. Duplicacy различает репозиторий (каталог с данными на клиенте) и storage (место, куда пишутся chunks), и синтаксис инициализации завязан на оба:
cd /srv/app
duplicacy init -encrypt app01-prod /mnt/backup/storage
duplicacy init -encrypt app01-prod sftp://backup@storage-host//srv/duplicacy
duplicacy init -encrypt app01-prod s3://eu-central-1@s3.amazonaws.com/my-bucket/repo
Первый аргумент — snapshot-id (уникальное имя источника данных), второй — URL хранилища. Флаг -encrypt включает шифрование chunks паролем, который Duplicacy запросит дважды при создании. Если репозиторий уже был инициализирован (например, скрипт деплоя случайно запускает init при каждом перезапуске), команда откажется с сообщением о существующей конфигурации — это не поломка, просто повторный init не нужен. Проверьте состояние без риска что-то сломать:
duplicacy check
duplicacy list
Пароль передавайте через переменную окружения, а не вводом в интерактивном скрипте:
export DUPLICACY_PASSWORD='ваш-пароль'
Для дополнительных хранилищ, добавленных командой duplicacy add <storage-name> <snapshot-id> <storage-url>, пароль читается из переменной с именем хранилища в верхнем регистре: DUPLICACY_<STORAGE-NAME>_PASSWORD. Отдельно и максимально серьёзно: пароль шифрования нигде не хранится на стороне Duplicacy и не восстанавливается — если хранилище зашифровано и пароль потерян, данные потеряны безвозвратно, никакого сброса через поддержку не существует. Держите пароль в менеджере паролей или в файле с правами 600 вне репозитория, а не в истории shell и не в переменной, которая попадёт в лог CI.
Несколько клиентов на одном хранилище: snapshot-id и chunk-уровень
Ключевая особенность Duplicacy — можно направить бэкапы с разных машин в одно и то же хранилище, и одинаковые блоки данных между ними задедуплицируются на уровне chunks без общего сервера блокировок. Работает это только при одном условии: у каждого клиента должен быть свой уникальный snapshot-id.
duplicacy init -encrypt db01-postgres s3://eu-central-1@s3.amazonaws.com/my-bucket/repo
duplicacy init -encrypt db02-postgres s3://eu-central-1@s3.amazonaws.com/my-bucket/repo
Частая ошибка — скопировать каталог .duplicacy/preferences с уже настроенным snapshot-id на вторую машину вместо того, чтобы инициализировать её отдельно. В результате два клиента пишут ревизии под одним и тем же именем: история снимков перемешивается, retention-политика prune применяется к обеим машинам как к одному источнику, и разобраться, какая ревизия с какого хоста, становится невозможно. Решение простое — всегда задавайте отдельный, осмысленный snapshot-id на каждой машине (hostname-роль, как в примере выше), даже если storage-url у всех одинаковый. Дедупликация на уровне chunks при этом никуда не денется: если на обеих БД лежат одинаковые файлы или совпадающие блоки, физически на хранилище они лягут один раз, а вот истории ревизий и политика хранения у каждого клиента останутся своими.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверЛокальное или SFTP-хранилище: права и путь
Если storage — обычный путь на диске или через SFTP, чаще всего спотыкаются на правах доступа и на том, что каталог существует, но реально ничего не смонтировано.
mountpoint -q /mnt/backup || { echo "backup disk not mounted"; exit 1; }
ls -la /mnt/backup
whoami
Duplicacy создаёт вложенную структуру каталогов под chunks при первом init, и если процесс бэкапа запущен от отдельного пользователя (что правильно — не гонять бэкап от root без необходимости), у него должны быть права на запись во всё дерево хранилища, а не только на чтение. Для SFTP Duplicacy использует встроенный SSH-клиент на базе golang.org/x/crypto/ssh, а не системный ssh, поэтому ключ нужно указывать явно и он должен быть без passphrase (или добавлен в ssh-agent), а формат URL — с двойным слэшем перед абсолютным путём:
duplicacy init -encrypt app01-prod sftp://backup@storage-host//srv/duplicacy/repo
Одинарный слэш после хоста укажет на путь относительно домашнего каталога пользователя backup, двойной — на абсолютный путь /srv/duplicacy/repo. Перепутанный слэш — частая причина, по которой бэкапы «работают», но пишутся не туда, куда ожидалось.
Фильтры .duplicacy/filters: бэкапится не то
В отличие от инструментов, которые по умолчанию уважают .gitignore, Duplicacy ничего не исключает автоматически. Правила задаются в файле .duplicacy/filters внутри репозитория, и здесь есть неочевидная деталь: правила применяются построчно сверху вниз, побеждает первое совпадение, а не самое специфичное.
+important.tmp
-*.tmp
-node_modules/
Если поменять первые две строки местами — -*.tmp перед +important.tmp — файл important.tmp попадёт под исключение раньше, чем до него дойдёт очередь правила-исключения, и в бэкап он не попадёт, хотя автор скрипта был уверен в обратном. Правило простое: сначала более специфичные include-правила для нужных исключений, затем более общие exclude. Проверить, что реально попадёт в снимок, можно без запуска полного бэкапа:
duplicacy backup -dry-run -stats
Вторая типичная ошибка — считать, что фильтры наследуются от .gitignore проекта. Это не так: если в репозитории уже есть .gitignore, его правила придётся либо продублировать в .duplicacy/filters вручную, либо принять, что Duplicacy будет бэкапить node_modules, vendor и прочий мусор, раздувая объём хранилища и время бэкапа.
prune и fossil collection: как правильно чистить старые ревизии
Retention-политика в Duplicacy задаётся флагами -keep n:m — хранить одну ревизию раз в n дней для снимков старше m дней:
duplicacy prune -keep 0:365 -keep 7:30 -keep 1:7
Это значит: удалить всё старше 365 дней, для снимков старше 30 дней оставлять одну ревизию в неделю, для снимков старше 7 дней — одну в день, более свежие не трогать. Здесь и кроется главная ловушка, связанная с той самой блокировкой на уровне chunks из шапки статьи: prune без дополнительных флагов не удаляет chunks сразу. Сначала они помечаются как fossils (переименовываются с суффиксом .fsl), и только следующий запуск prune удаляет их окончательно — но лишь убедившись, что ни один другой клиент, пишущий в то же хранилище, не мог их использовать в незавершённом бэкапе. Это и есть lock-free-механизм: вместо блокировки файла на время операции Duplicacy откладывает физическое удаление на шаг.
Проблема возникает, когда одна из машин, деливших хранилище, выводится из эксплуатации до того, как fossils после неё были собраны повторным прогоном prune: место на диске хранилища не освобождается, а бесхозные .fsl-файлы копятся бесконечно. Решение — либо выполнить финальный backup и prune перед выводом машины из эксплуатации, либо однократно прогнать prune -exclusive в окне обслуживания, когда точно известно, что параллельных бэкапов от других клиентов не идёт:
duplicacy prune -exclusive -keep 0:365 -keep 7:30 -keep 1:7
Флаг -exclusive пропускает двухшаговую схему и удаляет chunks сразу — это быстрее, но если в этот момент другая машина пишет в хранилище, можно получить chunk not found в её будущем бэкапе или восстановлении. Используйте -exclusive только когда уверены, что параллельной активности нет. Для сравнения: у restic нет мультиклиентского lock-free режима, поэтому такого класса проблем там не возникает — но нет и возможности безопасно шарить одно хранилище между независимыми машинами без внешней координации.
Восстановление: chunk not found и выбор ревизии
Список доступных ревизий и восстановление делаются так:
duplicacy list
duplicacy restore -r 42 -overwrite
Для восстановления в новое пустое место — например, на другой сервер после аварии — создайте пустой каталог, инициализируйте его с тем же snapshot-id и тем же storage-url, что и у исходного клиента, и только потом восстанавливайте:
mkdir /srv/app-restore && cd /srv/app-restore
duplicacy init app01-prod s3://eu-central-1@s3.amazonaws.com/my-bucket/repo
duplicacy restore -r 42
Ошибка chunk not found при восстановлении — самая неприятная, потому что проявляется в момент, когда бэкап уже действительно нужен. Три типичные причины: chunks удалены prune -exclusive, запущенным пока другой клиент ещё писал данные, ссылавшиеся на нужную ревизию (см. предыдущий раздел); кто-то вручную трогал структуру каталогов внутри storage — Duplicacy раскладывает chunks по вложенным подкаталогам по первым символам хеша, и любое ручное перемещение файлов внутри неё ломает адресацию; реже — рассинхронизация конфигурации после смены пароля шифрования без пересохранения существующих chunks.
Главный вывод — не полагаться на то, что бэкап есть, только потому что duplicacy backup отработал без ошибок. Регулярно проверяйте целостность:
duplicacy check -storage app01-prod
duplicacy check -chunks
Первая команда быстро проверяет, что все ревизии ссылаются на существующие chunks, вторая (медленнее и тяжелее по трафику) скачивает и проверяет содержимое самих chunks. Насколько ощутима нагрузка на сеть и сколько это займёт по времени — сильно зависит от объёма хранилища и канала до него, ориентируйтесь по факту на своих данных, а не по чужим цифрам. И минимум раз в квартал делайте тестовое восстановление на отдельный сервер — единственный способ по-настоящему знать, что бэкап рабочий, а не просто существует.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужен ли центральный сервер для координации нескольких клиентов Duplicacy?
Нет — в этом смысл lock-free-архитектуры: клиенты пишут в общее хранилище независимо, а безопасность параллельной записи и удаления обеспечивается двухшаговой схемой fossil collection на уровне chunks, а не отдельным сервисом блокировок.
Что будет, если забыть пароль зашифрованного хранилища?
Данные восстановить будет невозможно — пароль нигде не хранится на стороне Duplicacy, и обходного пути через поддержку не существует. Храните пароль в менеджере паролей или в защищённом файле отдельно от репозитория.
Можно ли бэкапить Linux, macOS и Windows в одно и то же хранилище?
Да, формат chunks и протокол хранения одинаковы на всех поддерживаемых платформах — именно поэтому Duplicacy удобен для разнородного парка серверов и рабочих станций с одной точкой хранения копий.
Почему prune не освобождает место на хранилище сразу?
Потому что первый запуск только помечает неиспользуемые chunks как fossils, а окончательно удаляет их следующий запуск prune — после того как убедится, что другие клиенты хранилища не могли на них ссылаться. Если один из клиентов выведен из эксплуатации до этого момента, fossils от него зависают — прогоните prune -exclusive вручную в окне без параллельных бэкапов.
Как понять, что фильтры .duplicacy/filters настроены верно?
Прогоните duplicacy backup -dry-run -stats и сверьте список файлов, которые попадут в снимок, до реального запуска — правила читаются построчно сверху вниз, и порядок include/exclude меняет результат.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →