Резервное копирование и аварийное восстановление GLPI: полное руководство

Рабочий план резервного копирования и аварийного восстановления GLPI: согласованный дамп, glpicrypt.key, о котором забывают почти все, ротация, отрепетированное тестовое восстановление и матрица решений RPO/RTO.

В этой статьеРазделов: 6

Резервная копия, которую ни разу не восстанавливали, — это надежда, а не стратегия. И в GLPI восстановление чаще всего срывается не из-за дампа базы, а из-за glpicrypt.key. При сопровождении клиентских сред мы уже видели «идеальное» восстановление базы, после которого никто не мог войти через LDAP и отправить e-mail: данные вернулись, но ключ, расшифровывающий пароли LDAP, SMTP и сборщика почты, остался позади. В этом руководстве собран план резервного копирования, ротации, тестового восстановления и аварийного восстановления, который мы применяем в продуктиве, с указанием мест, где всё действительно ломается.

Что действительно должно попасть в резервную копию

У GLPI три слоя состояния, и все три должны вернуться вместе и согласованно:

  • База данных — заявки, активы, пользователи, правила и настройки. Это сердце системы, но одна она среду не поднимет.
  • Каталог файлов (files/) — вложенные документы (files/_documents), изображения, XML-инвентаризации и данные плагинов. Если в базе есть строка документа, а сам файл не вернулся, пользователь нажимает на него и получает ошибку.
  • Конфигурация (config/) — config_db.php (хост, база и учётные данные) и, главное, glpicrypt.key. Этот ключ расшифровывает пароли, хранящиеся в базе: bind LDAP, сборщик почты (mailcollector), SMTP для уведомлений и секреты OAuth. Восстановление базы без него превращает все эти пароли в нерасшифровываемый мусор.

Внутри files/ резервировать нужно не всё. Временные каталоги вроде _cache, _tmp, _sessions, _cron и _lock создаются заново автоматически и только раздувают копию — исключите их. Сохранять важно _documents, _pictures, _uploads, _inventories и _plugins.

Согласованный дамп базы

GLPI 10 и 11 используют InnoDB во всех таблицах, поэтому --single-transaction делает согласованный снимок без блокировки приложения — пользователи продолжают создавать заявки во время резервного копирования. --quick не даёт загружать огромные таблицы в память, а --default-character-set=utf8mb4 предотвращает порчу диакритики и эмодзи. Никогда не передавайте пароль в командной строке (он виден в ps и в логах); используйте файл учётных данных с ограниченным доступом:

# ~/.my.cnf (chmod 600) - evita a senha no 'ps' e nos logs
[client]
host = 127.0.0.1
user = glpi
password = ...senha_do_glpi...

Встроенное резервное копирование GLPI (Администрирование > Обслуживание) записывает .sql в files/_dumps, но на больших базах оно обычно упирается в лимиты времени и памяти PHP. Для продуктива плановый mysqldump надёжнее.

Скрипт резервного копирования с ротацией

Единый скрипт, который обрабатывает базу, файлы и конфигурацию в правильном порядке и при этом удаляет всё старше 30 дней:

#!/usr/bin/env bash
set -euo pipefail

# Credenciais em ~/.my.cnf (chmod 600), nunca na linha de comando
DATA=$(date +%F)
DEST="/backup/glpi/${DATA}"
mkdir -p "${DEST}"

# Banco: snapshot consistente de InnoDB, sem travar a aplicacao
mysqldump --single-transaction --quick --routines --triggers \
  --default-character-set=utf8mb4 glpi \
  | gzip -6 > "${DEST}/glpi_db.sql.gz"

# Arquivos + config DEPOIS do dump (arquivo a mais e inofensivo;
# linha no banco apontando para arquivo ausente, nao)
tar -czf "${DEST}/glpi_files.tar.gz" \
  --exclude='files/_cache' --exclude='files/_tmp' \
  --exclude='files/_sessions' --exclude='files/_lock' \
  -C /var/www/glpi files config

# Rotacao: manter 30 dias
find /backup/glpi -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +

echo "Backup OK: ${DEST}"

Обратите внимание на порядок: дамп идёт до tar. Файл, появившийся на диске после дампа, при восстановлении безвреден; обратная ситуация — строка в базе, указывающая на файл, которого ещё не было, когда запускался tar, — превращается в битое вложение. Добавьте задание в cron:

# /etc/cron.d/glpi-backup - diario as 02h15
15 2 * * * root /opt/scripts/backup-glpi.sh >> /var/log/glpi-backup.log 2>&1

Матрица решений: RPO и RTO

Прежде чем определять частоту и срок хранения, ответьте на два вопроса: сколько данных бизнес готов потерять (RPO) и за какое время система должна снова заработать (RTO). Ответ зависит от критичности:

Профиль средыЦелевой RPOЦелевой RTOЧастота для базыСрок храненияВнешняя площадка
Тестовая / приёмочная24 чдниежедневно7 днейпо желанию
Стандартный продуктив24 ч4 чежедневно14–30 днейда (облако)
Критичный продуктив (SLA)15 мин1 чежедневно + binlog или реплика30–90 днейда, в зашифрованном виде

Это честные диапазоны, а не обещания. RPO в 15 минут требует binlog MariaDB/MySQL или реплики — одного ежедневного дампа для этого недостаточно.

Тестовое восстановление: шаг, который почти никто не делает

Резервная копия, которую ни разу не восстанавливали, — это цифра в отчёте, а не гарантия. Регулярно репетируйте восстановление в одноразовой среде — Docker идеально подходит — и никогда поверх продуктива:

# Ambiente DESCARTAVEL (Docker). Nunca ensaie por cima da producao.
mysql -u root -e "CREATE DATABASE glpi_restore CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"

# 1) Banco
zcat glpi_db.sql.gz | mysql --default-character-set=utf8mb4 -u root glpi_restore

# 2) Arquivos + config (INCLUI o config/glpicrypt.key)
tar -xzf glpi_files.tar.gz -C /var/www/glpi

# 3) Codigo mais novo que o dump? aplica a migracao de schema
php bin/console db:update --no-interaction

# 4) Limpa o cache e sobe para validar login/LDAP/e-mail
php bin/console cache:clear

После восстановления убедитесь, что состояние соответствует действительности, прежде чем ему доверять. Два быстрых запроса уже выявляют самые частые проблемы:

-- Versao gravada no banco (precisa casar com a do codigo antes do db:update)
SELECT value AS versao_db
FROM glpi_configs
WHERE context = 'core' AND name = 'version';

-- Quantos documentos apontam para um arquivo fisico em files/_documents
SELECT COUNT(*) AS docs_com_arquivo
FROM glpi_documents
WHERE filepath <> '';

Первый показывает версию, записанную в базе: если она ниже версии кода, схему согласует db:update. Второй считает документы, для которых ожидается файл на диске, — сравните с тем, что действительно пришло в files/_documents. В Docker те же шаги выполняются через docker exec -u www-data glpi php bin/console ....

Настоящее аварийное восстановление

Резервное копирование — это команда; аварийное восстановление — это план. Разумный минимум — правило 3-2-1: три копии на двух разных носителях, одна из них вне площадки. И здесь кроется типичная ошибка: сложить дамп базы и config/ (с glpicrypt.key) в один незашифрованный .tar и отправить его в бакет. Тот, кто получит этот файл, получит всю базу и ключ, расшифровывающий пароли LDAP, SMTP и сборщика почты, — то есть инфраструктурные учётные данные клиента в восстановимом виде. Внешняя резервная копия должна быть зашифрована (например, с помощью age или gpg) и иметь ограниченный доступ.

Завершите план письменным регламентом (runbook) — где лежат копии, в каком порядке восстанавливать, кто запускает процесс — и RTO, замеренным на реальной репетиции. При сопровождении разница между испугом и катастрофой никогда не сводилась к наличию резервной копии: решало то, что эту копию заранее восстановили с секундомером в руках и знают, что она поднимается за 40 минут, а не за «не знаю сколько».

Если ваш GLPI критичен и вы ни разу не замеряли полное восстановление — база, файлы и ключ шифрования вместе, — NexTool спроектирует и будет вести процесс резервного копирования и аварийного восстановления вашей среды с отрепетированным восстановлением и зашифрованной внешней копией. Обсудите с нами поддержку и сопровождение GLPI.


Проверено командой NexTool Solutions.

Часто задаваемые вопросы

Используйте mysqldump --single-transaction: поскольку в GLPI 10 и 11 все таблицы InnoDB, дамп получается согласованным без блокировки приложения, и пользователи продолжают создавать заявки. Сразу после этого сделайте копию файлов (files/) и конфигурации в том же скрипте, запускаемом по cron.

Это ключ, который расшифровывает пароли, хранящиеся в базе: bind LDAP, сборщик почты, SMTP для уведомлений и секреты OAuth. Если вы восстановили базу, но потеряли config/glpicrypt.key, эти пароли превращаются в нерасшифровываемый мусор, и вход через LDAP и отправка почты перестают работать. Всегда резервируйте config/ вместе с базой.

База: для продуктива минимум ежедневно. Файлы: ежедневно или еженедельно, в зависимости от объёма вложений. Для короткого RPO (15–30 минут) нужен binlog MariaDB или реплика; один ежедневный дамп даёт RPO до 24 часов.

Регулярно восстанавливайте её в одноразовой среде (Docker), никогда поверх продуктива. Запустите GLPI, войдите, откройте старую заявку с вложением и проверьте LDAP и отправку почты. Замерьте время процесса: это и есть ваш реальный RTO. Ни разу не восстановленная резервная копия — не гарантия.

Да, если код той же версии или новее дампа. Восстановите базу, а затем выполните php bin/console db:update, чтобы мигрировать схему. Никогда не восстанавливайте более новый дамп на более старом коде: структура не откатывается, и среда ломается.

Принцип тот же: docker exec в контейнер базы для mysqldump и tar смонтированных томов files/ и config/. Зафиксируйте версию образа (не используйте :latest), чтобы восстановление попало на код, совместимый с дампом.

Нужна помощь?