Бэкап и восстановление Harbor
Harbor — это свой приватный реестр Docker-образов со сканированием на уязвимости и RBAC поверх обычного docker registry, а внутри него — не один сервис, а связка из PostgreSQL, Redis, файлового или S3-хранилища блобов и отдельного секретного ключа. Именно поэтому «бэкап Harbor» нельзя свести к tar -czf backup.tar.gz /data — часть данных в этом каталоге без базы бесполезна, а часть секретов вообще лежит отдельно. Разберём, что реально нужно сохранить, как это сделать без порчи консистентности и как потом поднять Harbor заново на новом сервере.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Из чего состоит Harbor и что тут вообще бэкапить
Типовая установка Harbor через официальный офлайн- или онлайн-инсталлятор разворачивается как набор Docker-контейнеров через docker-compose, у которых есть три категории данных с разной логикой резервного копирования:
- База данных PostgreSQL — проекты, пользователи, RBAC-политики, робот-аккаунты (зашифрованные), метаданные тегов образов, результаты сканирования Trivy, вебхуки, квоты.
- Хранилище блобов (registry storage) — сами слои образов и манифесты. По умолчанию это локальная файловая система в
/data/registry, но Harbor умеет работать и с S3-совместимым backend, включая свой же MinIO. - Секреты и конфигурация —
harbor.yml, файл/data/secret/keys/secretkey, TLS-сертификаты, конфиг job service и логи.
Redis в этой схеме держит только кеш и очереди задач — терять его не страшно, после рестарта он соберётся заново из PostgreSQL и текущего состояния. А вот secretkey — это симметричный ключ, которым Harbor шифрует пароли робот-аккаунтов и LDAP-bind-пароль прямо в базе. Потерять его вместе с базой не критично, а вот потерять только его, оставив базу, — критично: все зашифрованные секреты в БД станут нечитаемыми, и робот-аккаунты придётся пересоздавать заново.
Проверить, где физически лежат данные вашей установки, можно в harbor.yml:
grep -A2 "^data_volume" /opt/harbor/harbor.yml
По умолчанию это /data на хосте, и внутри него уже разложены database, registry, redis, secret, job_logs — но если вы явно указывали другой путь при установке, дальше по тексту подставляйте свой.
Бэкап базы данных: pg_dump, а не копирование файлов
PostgreSQL в Harbor крутится как обычный контейнер, и «на горячую» просто скопировать /data/database нельзя — файлы страниц могут оказаться в промежуточном состоянии между двумя транзакциями. Правильный способ — логический дамп через pg_dump/pg_dumpall прямо из контейнера, благо PostgreSQL умеет делать консистентный снепшот без остановки сервиса:
# имя контейнера БД зависит от версии установки, обычно harbor-db
docker exec -t harbor-db pg_dumpall -c -U postgres \
> /backup/harbor/harbor-db-$(date +%F).sql
# альтернатива точечно по базам Harbor, если не нужны роли и пользователи Postgres целиком
docker exec -t harbor-db pg_dump -U postgres -d registry \
> /backup/harbor/harbor-registry-db-$(date +%F).sql
pg_dumpall тяжелее по объёму, зато при восстановлении сразу восстанавливает и роли, и права доступа — для Harbor это удобнее, поскольку схема БД использует несколько логических баз (registry, notary_signer при включённом Notary и т.д.), и pg_dumpall заберёт их все одной командой. Дамп текстовый, поэтому его стоит сразу сжать:
gzip /backup/harbor/harbor-db-$(date +%F).sql
Полезно проверять размер результата — если дамп внезапно стал в разы меньше вчерашнего, это почти всегда означает, что pg_dump упал с ошибкой на середине, а не что база правда похудела.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверБэкап хранилища образов: файловая система или S3-backend
Если Harbor настроен на локальный диск (значение по умолчанию в harbor.yml — filesystem), блобы лежат в /data/registry плоской структурой по content-addressable хешам. Копировать их можно любым инструментом файлового бэкапа, важно только не запускать сборку мусора (garbage collection) параллельно с копированием — GC перекладывает и удаляет неиспользуемые блобы, и снимок, сделанный в этот момент, может получиться несогласованным с манифестами из уже снятого дампа БД.
# rsync с сохранением прав и жёстких ссылок
rsync -aH --delete /data/registry/ /backup/harbor/registry/
# либо через restic для дедупликации и версионирования — подробнее в статье
# про restic и borgbackup: /blog/restic-ili-borgbackup-chto-vygodnee-i-kogda/
restic -r /backup/harbor-restic backup /data/registry
Если вместо файловой системы используется S3-совместимое хранилище (в harbor.yml в секции storage_service указан s3 или адрес MinIO), сами блобы бэкапить отдельным шагом не нужно — этим занимается уже бэкап самого объектного хранилища, а Harbor тут выступает просто клиентом. В таком случае для Harbor остаются только БД и секреты — это заметно упрощает схему на больших реестрах, где счёт блобов идёт на сотни гигабайт.
Перед бэкапом файлового хранилища стоит поставить Harbor на паузу для job service, чтобы не ловить гонку с GC:
# отключаем джобы через API или UI: Administration → Garbage Collection → отменить расписание
# либо временно останавливаем сервис задач
docker stop harbor-jobservice
# ...бэкап...
docker start harbor-jobservice
Секретный ключ и конфигурация: маленький файл с большими последствиями
Файл /data/secret/keys/secretkey — 16 байт, но без него после восстановления не расшифруются пароли робот-аккаунтов и bind-пароль LDAP/AD, хранящиеся в БД. Бэкапить его нужно отдельно от общей файловой копии и хранить так же бережно, как приватный ключ TLS:
cp /data/secret/keys/secretkey /backup/harbor/secretkey-$(date +%F)
chmod 600 /backup/harbor/secretkey-*
Вместе с ним имеет смысл сохранить конфигурацию установки — она не критична для целостности данных, но без неё восстановление на новом сервере превращается в ручной подбор параметров:
cp /opt/harbor/harbor.yml /backup/harbor/harbor.yml-$(date +%F)
cp /opt/harbor/docker-compose.yml /backup/harbor/docker-compose.yml-$(date +%F)
tar -czf /backup/harbor/common-config-$(date +%F).tar.gz /opt/harbor/common
Каталог common — это результат работы установочного скрипта prepare: там лежат сгенерированные конфиги nginx, core, jobservice и TLS-сертификаты. Если вы используете свои сертификаты (не самоподписанные, сгенерированные при установке), их стоит бэкапить как обычные секреты сервера — принципы те же, что описаны в статье про управление секретами Docker.
Автоматизация: один скрипт и cron
Собрать три источника в один скрипт проще, чем помнить порядок действий в момент реального инцидента:
#!/usr/bin/env bash
# /usr/local/bin/harbor-backup.sh
set -euo pipefail
DATE=$(date +%F)
DEST=/backup/harbor/$DATE
mkdir -p "$DEST"
docker exec -t harbor-db pg_dumpall -c -U postgres | gzip > "$DEST/db.sql.gz"
cp /data/secret/keys/secretkey "$DEST/secretkey"
cp /opt/harbor/harbor.yml "$DEST/harbor.yml"
tar -czf "$DEST/common-config.tar.gz" -C /opt/harbor common
# только если storage_service = filesystem
rsync -aH /data/registry/ "$DEST/registry/"
chmod -R 600 "$DEST"
find /backup/harbor -maxdepth 1 -mtime +14 -exec rm -rf {} \;
# /etc/cron.d/harbor-backup
0 3 * * * root /usr/local/bin/harbor-backup.sh >> /var/log/harbor-backup.log 2>&1
Отдельная резервная копия локально на том же сервере не спасёт от отказа диска или всего хоста — итоговый каталог /backup/harbor стоит синхронизировать на другой сервер или в объектное хранилище тем же mc mirror или restic, аналогично тому, как это делается для бэкапа Docker volume.
Восстановление Harbor на новом сервере
Восстановление предполагает установку Harbor той же версии, что была на источнике — схема БД между мажорными версиями меняется миграциями, и накатывать старый дамп на новый Harbor напрямую не поддерживается. Порядок действий:
- Установите Docker и docker-compose, скачайте офлайн-инсталлятор Harbor нужной версии, распакуйте.
- Верните конфигурацию: положите сохранённый
harbor.ymlна место, распакуйтеcommon-config.tar.gzв/opt/harbor/common(либо просто заново прогоните./prepare, если сертификаты не критичны и можно выпустить новые). - Верните секретный ключ до первого запуска контейнеров:
mkdir -p /data/secret/keys
gunzip -c /backup/harbor/db.sql.gz > /tmp/db.sql # если сжимали
cp /backup/harbor/secretkey /data/secret/keys/secretkey
chmod 600 /data/secret/keys/secretkey
- Поднимите только контейнер БД, без остальных сервисов, восстановите дамп:
docker compose up -d harbor-db
sleep 10
cat /tmp/db.sql | docker exec -i harbor-db psql -U postgres
- Верните файлы реестра (если хранилище — filesystem):
rsync -aH /backup/harbor/registry/ /data/registry/
- Запустите Harbor целиком и проверьте, что данные на месте:
docker compose up -d
docker compose ps
curl -sk https://localhost/api/v2.0/health | python3 -m json.tool
- Залогиньтесь в UI, проверьте список проектов, попробуйте
docker pullодин из старых образов и убедитесь, что робот-аккаунт всё ещё аутентифицируется старым токеном — это и есть проверка того, что secretkey встал на место корректно.
Если восстанавливаете не на идентичной, а на более новой версии Harbor, после шага 6 нужно выполнить официальную процедуру миграции БД (harbor-migrate из соответствующего релиза) до включения сервисов — иначе core-контейнер откажется стартовать из-за несовпадения версии схемы. Подробное описание процедуры и конкретных ошибок при её запуске полезно смотреть в статье про частые проблемы приватного Docker-registry, там же разбирается похожая история с версионированием при апгрейде.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли бэкапить Harbor одним docker-compose down и копированием всего /data?
Технически да, если сервисы полностью остановлены и БД не пишет в момент копирования — тогда файловый снимок будет консистентным. Но это требует простоя реестра на время бэкапа, что неудобно для CI/CD-пайплайнов, которые тянут образы круглосуточно. pg_dump на живой базе даёт консистентный снимок без остановки сервисов, поэтому в проде обычно используют именно его.
Что будет, если восстановить базу без secretkey?
Робот-аккаунты и сохранённый LDAP bind-пароль перестанут работать — Harbor не сможет их расшифровать. Проекты, теги и права доступа при этом не пострадают, но робот-аккаунты придётся пересоздать заново вручную через UI или API.
Обязательно ли использовать S3-совместимое хранилище вместо локального диска?
Нет, для небольшого и среднего реестра локальной файловой системы достаточно, и она проще в бэкапе — не нужен отдельный сервис. S3-backend имеет смысл, если реестр уже большой, нужна репликация между локациями или горизонтальное масштабирование core-сервиса за балансировщиком.
Как проверить, что бэкап реально рабочий, не поднимая прод-сервер заново?
Разверните тестовый Harbor той же версии на отдельной VPS, накатите на него дамп БД и secretkey, подключите тестовый docker login и потяните один образ. Это тот же принцип, что и для любых других бэкапов баз данных — держать нетестированную копию имеет смысл ровно до первого реального восстановления.
Нужно ли отдельно бэкапить результаты сканирования Trivy?
Они хранятся в той же БД PostgreSQL, что и остальные метаданные, поэтому отдельного шага не требуется — pg_dump заберёт их вместе со всем остальным. Кеш самой базы уязвимостей Trivy пересобирается автоматически при следующем обновлении и бэкапить его нет смысла.
Что делать, если между бэкапом и восстановлением вышла новая версия Harbor и старый инсталлятор уже недоступен?
Официальные релизы Harbor остаются доступны в GitHub releases проекта за все прошлые версии, включая офлайн-инсталляторы — важно скачать версию, совпадающую с той, что стояла на момент снятия дампа, а уже после восстановления накатывать миграции поверх неё по официальной инструкции апгрейда.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →