MAATRIX / Блог / Бэкап и восстановление GitLab CE

Бэкап и восстановление GitLab CE

MAATRIX

Если self-hosted GitLab CE — это единственное место, где живут ваши репозитории, issues, CI/CD пайплайны и реестр контейнеров, то потеря сервера без свежего бэкапа означает потерю всей истории разработки за один вечер. Штатная утилита gitlab-backup делает архив данных, но без отдельного сохранения конфига и файла секретов этот архив бесполезен — восстановленный GitLab просто не расшифрует пароли и токены. Разберём, как бэкапить GitLab CE правильно и как проверенно восстанавливать его после сбоя.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что именно нужно бэкапить в GitLab CE

GitLab CE хранит данные в трёх принципиально разных местах, и бэкапить их нужно по-разному:

  • Данные приложения — репозитории Git, база PostgreSQL, issues, merge requests, вложения, artifacts CI/CD, container registry. Это то, что сохраняет штатная команда gitlab-backup create.
  • Секреты — файл /etc/gitlab/gitlab-secrets.json с ключами шифрования для паролей пользователей, токенов CI, OAuth-настроек и 2FA. Без него данные из основного бэкапа не расшифровываются — это самая частая причина, по которой люди теряют GitLab после "успешного" восстановления.
  • Конфигурация/etc/gitlab/gitlab.rb (omnibus-установка) или docker-compose.yml и переменные окружения (docker-установка): домен, SMTP, SSL, лимиты, внешние интеграции.

Штатный gitlab-backup create не трогает gitlab.rb и gitlab-secrets.json — это осознанное решение разработчиков GitLab, чтобы бэкап данных и бэкап секретов можно было хранить в разных местах с разным уровнем доступа. Но на практике это означает, что нужно настраивать два независимых процесса бэкапа, и оба обязательны.

Также по умолчанию gitlab-backup create не включает container registry (образы Docker) — это нужно явно разрешить в gitlab.rb, иначе после восстановления реестр окажется пустым при полностью рабочей базе данных.

Полный бэкап на omnibus-установке (Ubuntu/Debian, пакет gitlab-ce)

Если GitLab установлен из официального .deb-пакета (омнибас-сборка), бэкап делается одной командой:

sudo gitlab-backup create

Архив попадёт в /var/opt/gitlab/backups/ с именем вида 1735689600_2026_08_31_16.11.0_gitlab_backup.tar. Число в начале — unix-timestamp, дальше версия GitLab: это важно, потому что восстановить бэкап можно только на ту же минорную версию GitLab, на которой он был сделан.

Полезные опции при создании бэкапа:

# исключить artifacts и registry из бэкапа (если храните их отдельно)
sudo gitlab-backup create SKIP=artifacts,registry

# только данные приложения без пропуска — с явным включением registry
sudo gitlab-backup create SKIP=

# ограничить время ожидания блокировки БД (для больших инстансов)
sudo gitlab-backup create GITLAB_BACKUP_MAX_CONCURRENCY=4

Доступные значения для SKIP: db, uploads, repositories, builds, artifacts, lfs, registry, pages. Чем крупнее инстанс (много LFS-объектов или большой registry), тем чаще имеет смысл выносить их бэкап на уровень объектного хранилища отдельно, а gitlab-backup использовать только для БД и репозиториев.

Проверьте, включён ли бэкап registry, в /etc/gitlab/gitlab.rb:

gitlab_rails['backup_upload_connection'] = {...}  # опционально, для загрузки в S3-совместимое хранилище
registry['registry_http_addr'] = "localhost:5000"

Сам registry попадёт в бэкап автоматически, если он включён в конфиге — отдельно ничего активировать не нужно, но стоит проверить размер: registry часто оказывается самой тяжёлой частью архива.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Бэкап GitLab CE в Docker / docker-compose

При установке через docker-compose (образ gitlab/gitlab-ce) команда бэкапа выполняется через docker exec:

docker exec -t gitlab gitlab-backup create

Архив создаётся внутри контейнера в /var/opt/gitlab/backups/, но если этот путь смонтирован в docker-compose.yml как volume — а это должно быть сделано изначально — файл сразу появится и на хосте:

services:
  gitlab:
    image: gitlab/gitlab-ce:17.4.1-ce.0
    volumes:
      - ./gitlab/config:/etc/gitlab
      - ./gitlab/logs:/var/log/gitlab
      - ./gitlab/data:/var/opt/gitlab
      - ./gitlab/backups:/var/opt/gitlab/backups

Если volume для backups отдельно не выделен, архив останется только внутри слоя контейнера — при пересоздании контейнера (docker-compose down без -v, обновление образа) он не потеряется, но лучше не полагаться на это и смонтировать отдельную директорию явно.

Для docker-инсталляции стратегия копирования данных отличается — по умолчанию GitLab пытается сделать hard link для репозиториев, что в контейнерных FS иногда не работает между разными volume. Если видите ошибки вида Invalid cross-device link, используйте:

docker exec -t gitlab gitlab-backup create STRATEGY=copy

Это медленнее (полное копирование вместо hard link), зато работает надёжно поверх любых volume-драйверов.

Отдельное сохранение секретов и конфигурации

Это тот шаг, который обязательно нужен и который чаще всего забывают. Без него у вас будет "рабочий" бэкап, который невозможно осмысленно восстановить.

Omnibus-установка:

sudo cp /etc/gitlab/gitlab-secrets.json /root/gitlab-config-backup/
sudo cp /etc/gitlab/gitlab.rb /root/gitlab-config-backup/

Docker-установка — файлы лежат в смонтированной директории config на хосте, их достаточно копировать оттуда же:

cp ./gitlab/config/gitlab-secrets.json /root/gitlab-config-backup/
cp ./gitlab/config/gitlab.rb /root/gitlab-config-backup/

Оба файла нужно хранить вместе с архивом данных, но в идеале с раздельным контролем доступа — секреты можно шифровать дополнительно перед выгрузкой во внешнее хранилище:

tar czf - gitlab-secrets.json gitlab.rb | \
  gpg --symmetric --cipher-algo AES256 -o gitlab-config-$(date +%F).tar.gz.gpg

Без пароля от этого gpg-архива восстановление на новом сервере станет невозможным — храните пароль отдельно от самого сервера (менеджер паролей, а не текстовый файл рядом с бэкапом).

Автоматизация и хранение бэкапов вне сервера

Локальный бэкап на том же диске, где живёт продакшн-GitLab, защищает от человеческой ошибки (случайно удалили проект), но не защищает от потери сервера целиком. Схема "3-2-1" здесь применяется буквально: минимум одна копия должна физически лежать не на этой машине.

Пример cron-задачи с ротацией и выгрузкой в S3-совместимое хранилище через rclone:

# /etc/cron.d/gitlab-backup
0 3 * * * root /usr/bin/gitlab-backup create CRON=1 >> /var/log/gitlab-backup.log 2>&1
30 3 * * * root /usr/local/bin/gitlab-backup-offsite.sh
#!/bin/bash
# /usr/local/bin/gitlab-backup-offsite.sh
set -euo pipefail

BACKUP_DIR="/var/opt/gitlab/backups"
LATEST=$(ls -t "$BACKUP_DIR"/*_gitlab_backup.tar | head -n1)

rclone copy "$LATEST" remote:gitlab-backups/data/
rclone copy /root/gitlab-config-backup/ remote:gitlab-backups/config/

# ротация: держим на remote только последние 14 копий
rclone ls remote:gitlab-backups/data/ | sort -k2 | head -n -14 | \
  awk '{print $2}' | xargs -I{} rclone delete remote:gitlab-backups/data/{}

Флаг CRON=1 в gitlab-backup create подавляет вывод в stdout, если он не завершился с ошибкой — это важно, чтобы cron не заваливал почту root по расписанию каждую ночь.

По умолчанию gitlab.rb также хранит настройку gitlab_rails['backup_keep_time'] — сколько секунд хранить старые бэкапы локально перед автоматическим удалением. Разумное значение для сервера с ограниченным диском — 604800 (7 дней), при условии что offsite-копия настроена отдельно и хранится дольше.

Восстановление GitLab CE из бэкапа

Восстановление — это ровно та операция, которую нужно один раз протестировать заранее на отдельном сервере, а не в момент реального инцидента. Порядок действий:

1. Разверните GitLab той же версии, на которой был сделан бэкап. Версию видно в имени файла архива:

sudo apt-get install gitlab-ce=17.4.1-ce.0

2. Восстановите секреты и конфиг до первого запуска, если разворачиваете на чистом сервере:

sudo cp gitlab-secrets.json /etc/gitlab/
sudo cp gitlab.rb /etc/gitlab/
sudo gitlab-ctl reconfigure

3. Остановите сервисы, которые обращаются к БД, но оставьте работать сам Puma/Sidekiq control-процессы через unicorn/puma-worker gitlab-ctl умеет сам:

sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq

4. Положите архив в /var/opt/gitlab/backups/ и запустите восстановление:

sudo cp 1735689600_2026_08_31_16.11.0_gitlab_backup.tar /var/opt/gitlab/backups/
sudo gitlab-backup restore BACKUP=1735689600_2026_08_31_16.11.0

Обратите внимание: параметр BACKUP= — это timestamp и версия из имени файла, без суффикса _gitlab_backup.tar.

5. Запустите сервисы обратно и проверьте целостность:

sudo gitlab-ctl start
sudo gitlab-rake gitlab:check SANITIZE=true

Для docker-установки все команды выполняются через docker exec -t gitlab ... аналогично, при условии что архив и конфиги смонтированы в контейнер тем же образом, что при бэкапе.

Частая проблема после восстановления — права доступа на файлы репозиториев не совпадают с пользователем git, под которым работает GitLab:

sudo chown -R git:git /var/opt/gitlab/git-data/repositories

Ещё одна частая ошибка — попытка восстановить бэкап на другую минорную версию GitLab. Формально gitlab-backup restore может даже не выдать ошибку сразу, но миграции БД потом ломаются непредсказуемо. Правило простое: версия сервера при восстановлении должна совпадать с версией из имени файла бэкапа, при необходимости — сначала восстановить на той же версии, а затем последовательно обновиться штатным способом.

Если разворачиваете GitLab на новом сервере с нуля под задачу CI/CD и self-hosted репозиториев, схема разметки диска и объём RAM для инстанса с runner'ами отличаются от чисто веб-нагрузки — это стоит спланировать заранее, а не после первого падения из-за нехватки памяти при сборке.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли восстановить только один проект из полного бэкапа, не разворачивая весь инстанс?

Штатно — нет, gitlab-backup restore работает только с полным архивом целиком. Для точечного восстановления одного репозитория проще развернуть GitLab на тестовом сервере из полного бэкапа, а затем экспортировать нужный проект через встроенный экспорт проекта (Project export) и импортировать его в продакшн.

Что делать, если бэкап делается дольше и дольше с ростом инстанса?

Вынести LFS-объекты, artifacts и registry в object storage (S3-совместимое) через настройки gitlab.rb — тогда gitlab-backup create будет резервировать только БД и Git-репозитории, а сами файлы бэкапятся отдельно средствами хранилища.

Нужно ли останавливать GitLab на время создания бэкапа?

Нет, gitlab-backup create штатно работает на живом инстансе и использует блокировки на уровне транзакций БД. Останавливать сервисы нужно только на этапе восстановления (gitlab-backup restore), не при создании архива.

Как проверить, что бэкап рабочий, не разворачивая продакшн заново?

Регулярно (например, раз в месяц) поднимайте GitLab той же версии на отдельном тестовом VPS и выполняйте полное восстановление по инструкции выше. Это единственный надёжный способ убедиться, что архив, секреты и конфиг действительно совместимы — доверять факту "архив создался без ошибок" не стоит.

Что будет с CI/CD runner'ами после восстановления GitLab?

Сами runner'ы регистрируются отдельно и не входят в бэкап GitLab — после восстановления сервера их токены регистрации остаются рабочими, если runner подключался по URL инстанса и токену проекта/группы, но стоит проверить gitlab-runner verify на каждой runner-машине.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →