Резервное копирование¶
Что в установке Taimen нужно бэкапить, как снимать дампы каждой базы, какие особенности есть у базы памяти и как восстановить установку целиком или по частям. Статья для инженера эксплуатации.
Что бэкапить¶
Сервисы платформы stateless: всё состояние лежит в томах Docker и в нескольких файлах на хосте.
| Объект | Где | Содержимое | Критичность |
|---|---|---|---|
| БД IAM | том iam_db, сервис iam-db, БД iam |
Tenants, principals, хэши PAT, service accounts, audiences, audit, outbox | Критично |
| БД Control Plane | том control_plane_db, сервис control-plane-db, БД control_plane |
Задачи, claims, runs, артефакты, approvals, журнал событий и его архив, курсоры потребителей, IAM bindings | Критично |
| БД памяти | том memory_db, сервис memory-db, БД company_brain |
Граф знаний (таблицы PostgreSQL), чанки и вектора (pgvector), наблюдения, трассы контекста | Критично; содержит данные заказчика, возможно ПДн |
| БД Keycloak | том keycloak_db, сервис keycloak-db, БД keycloak |
Живой realm, пользователи и их пароли | Критично при профиле idp: без неё людей заводят заново |
| Объекты MinIO | том platform_minio |
Содержимое артефактов Control Plane (бакет CP_S3_BUCKET) |
Критично: MinIO входит в профиль core; бэкапить вместе с control-plane-db |
| Сертификаты | том caddy_data |
Сертификаты, ключи, ACME-аккаунт | Желательно: без него сертификаты выпускаются заново |
| Конфигурация | .env, secrets/, deploy/state/<env>.json, Caddyfile установки |
Секреты, ключ подписи IAM, PAT, идентификаторы bootstrap | Критично; хранить отдельно и шифровать |
Имена томов в Docker — с префиксом проекта:
${COMPOSE_PROJECT_NAME}_iam_db и т. д. (переопределяются переменными
VOLUME_* в .env). Точный список:
Ключ подписи IAM и .env — часть бэкапа
Без secrets/iam-signing.pem восстановленная БД IAM выдаёт токены
новым ключом — это переживаемо. Без .env не подойдут пароли к
восстановленным томам, а без deploy/state/<env>.json повторный
bootstrap заведёт tenant и principals заново. Храните конфигурацию
отдельно от дампов, в зашифрованном виде.
Runner-хост критичных данных не хранит: рабочие копии воссоздаются из bare-зеркал, опубликованные ветки задач лежат в forge. Потеряется только неопубликованная работа текущих задач.
Логические дампы PostgreSQL¶
Все базы снимаются pg_dump в формате custom изнутри контейнеров. Базы
разные и восстанавливаются независимо; внутри Control Plane состояние,
журнал, архив и курсоры лежат в одной базе и согласованы одним дампом.
| Сервис | Пользователь | База |
|---|---|---|
iam-db |
iam |
iam |
control-plane-db |
control_plane |
control_plane |
memory-db |
memory |
company_brain |
keycloak-db |
keycloak |
keycloak |
Скрипт ежедневного бэкапа¶
#!/usr/bin/env bash
# /opt/taimen/backup.sh — дампы всех поднятых БД + конфигурация + тома без СУБД
set -euo pipefail
cd /opt/taimen/src
STAMP=$(date -u +%Y%m%dT%H%MZ)
OUT=/opt/taimen/backups/$STAMP
mkdir -p "$OUT" && chmod 700 "$OUT"
DC=(tools/compose --profile "*")
dump() { # dump <сервис> <пользователь> <база>
if "${DC[@]}" ps --status running --services | grep -qx "$1"; then
"${DC[@]}" exec -T "$1" pg_dump -U "$2" -d "$3" -Fc > "$OUT/$1-$3.dump"
fi
}
dump iam-db iam iam
dump control-plane-db control_plane control_plane
dump memory-db memory company_brain
dump keycloak-db keycloak keycloak
# Конфигурация (секреты!) — отдельным архивом
tar czf "$OUT/config.tgz" .env secrets deploy/state /opt/taimen/Caddyfile
# Тома без СУБД: сертификаты и объекты MinIO
vol() { docker run --rm -v "$1":/data:ro -v "$OUT":/backup alpine tar czf "/backup/$1.tgz" -C /data .; }
P=${COMPOSE_PROJECT_NAME:-taimen}
vol "${P}_caddy_data"
docker volume inspect "${P}_platform_minio" >/dev/null 2>&1 && vol "${P}_platform_minio"
chmod 600 "$OUT"/*
find /opt/taimen/backups -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +
Запуск по расписанию (systemd timer или cron) и перед каждой выкладкой:
Бэкап на том же диске — не бэкап
Копируйте каталог дампов за пределы хоста и шифруйте: дампы памяти
содержат данные заказчика, дамп IAM — хэши credential'ов,
config.tgz — секреты в открытом виде.
Согласованность между базами¶
Дампы разных баз снимаются в разные моменты. Платформа это переносит:
- Control Plane ↔ память. Доставка в память идёт через outbox и курсор
context-adapter, лежащие в базе Control Plane. Если память восстановлена из более старого дампа, чем Control Plane, выполните:rebuild— адаптер переиграет журнал, память дедуплицирует повторы поevent:<uuid>. Если наоборот — адаптер доставит часть событий повторно, что тоже безопасно. - IAM ↔ Control Plane. Bindings лежат в Control Plane, principals и PAT — в IAM. Principal, созданный после дампа IAM, при восстановлении пропадёт; его binding в Control Plane перестанет срабатывать (вход закроется) — перевыпустите principal и binding.
- Control Plane ↔ MinIO. Записи артефактов (размер, media type,
SHA-256) в базе Control Plane, байты — в MinIO. Копию тома снимайте
после дампа базы: объекты неизменяемы, и всё, на что ссылается дамп,
уже лежит в томе. Если том окажется старше базы, выдача части артефактов
ответит
503 content_store_unavailable. Подробнее — в Хранилище объектов.
Особенность памяти: граф в таблицах PostgreSQL¶
memory-db — PostgreSQL 16 с расширениями pgvector и pg_trgm. Граф памяти —
обычные таблицы graph_nodes и graph_edges в схеме CB_GRAPH_NAME
(MEM-ADR-023), поэтому особых шагов нет: база снимается pg_dump и
восстанавливается pg_restore, в том числе в другой кластер (новый том, новый
хост).
tools/compose stop memory-service
tools/compose exec -T memory-db pg_restore -U memory -d company_brain \
--clean --if-exists --no-owner < backups/<stamp>/memory-db-company_brain.dump
tools/compose up -d memory-service
curl -fsS http://127.0.0.1:18001/healthz # {"ok": true, "graph": ..., "nodes": N, "chunks": M}
Установка, где граф ещё в Apache AGE
До memory-service v0.2.1 граф хранился в Apache AGE. Дамп такой установки
восстанавливается так же (образ memory-db поставки основан на образе
Apache AGE, расширение в нём есть), а затем граф переносится в таблицы
командой cb migrate-graph-from-age при остановленном сервисе: сначала
--dry-run, потом перенос. После запуска сервиса перенос повторно не
запускайте. Команда читает таблицы меток AGE напрямую, мимо каталога,
поэтому правка OID каталога AGE для переноса не нужна. Подробно — в
Конфигурации памяти.
После любого восстановления памяти сверяйте счётчики nodes и chunks из
/healthz со значениями до инцидента.
Восстановление¶
Одна база Control Plane¶
tools/compose stop control-plane-worker context-adapter control-plane-api
tools/compose exec -T control-plane-db pg_restore -U control_plane -d control_plane \
--clean --if-exists --no-owner < backups/<stamp>/control-plane-db-control_plane.dump
tools/compose up -d control-plane-api # применит миграции, если дамп старее
curl -fsS http://127.0.0.1:18000/health/ready # 503 migrations_pending, пока ревизия отстаёт
tools/compose up -d control-plane-worker context-adapter
Частичное восстановление отдельных таблиц Control Plane не поддерживается: журнал, состояние и курсоры связаны инвариантами (append-only, внешние ключи, позиции курсоров).
Если после восстановления память опережает журнал — ничего делать не нужно. Если память отстаёт или потеряна — перестройте доставку:
curl -s -X POST http://127.0.0.1:18000/api/v1/operations/context-adapter/<tenant-id>:rebuild \
-H "Authorization: Bearer <admin access token>" -H 'Content-Type: application/json' \
-d '{"reason": "memory restored from backup"}'
База IAM¶
tools/compose stop iam-service
tools/compose exec -T iam-db pg_restore -U iam -d iam --clean --if-exists --no-owner \
< backups/<stamp>/iam-db-iam.dump
tools/compose up -d iam-service
Отзывы после даты дампа теряются
Восстановленная база IAM не знает об отзывах PAT и service accounts, сделанных после снятия дампа: такие credentials снова становятся действительными. Сразу после восстановления повторите отзывы по журналу инцидентов или внешнему журналу операций.
Полное восстановление на новый хост¶
- Подготовьте хост по Промышленному развёртыванию, клонируйте суперпроект на том же коммите, что работал до аварии.
- Распакуйте
config.tgz:.env,secrets/,deploy/state/, Caddyfile. Восстановите владельца ключей:chown 10001:10001 secrets/*.pem. -
Восстановите том
caddy_dataдо первого запускаcaddy: -
Поднимите только базы и дождитесь
healthy: -
Восстановите каждую базу
pg_restore --clean --if-exists --no-owner. - Для памяти: если граф установки ещё в Apache AGE, перенесите его
cb migrate-graph-from-ageдо запуска memory-service (см. выше); затем проверьте/healthz. - Восстановите том MinIO (
platform_minio) тем же способом, чтоcaddy_data: в нём содержимое артефактов ядра. Если ядро работает с внешним S3 (deploy/local/compose.s3.example.yml), восстановите бакет средствами провайдера. - Поднимите всё:
tools/compose --profile core --profile edge … up -d. - Проверьте
make smoke,/health/ready, вход оператора, метрикуcontext_adapter_parked_tenants. - Переключите DNS на новый хост.
Проверка бэкапов¶
Бэкап, который ни разу не восстанавливали, — гипотеза. Раз в месяц:
- поднимите копию установки на отдельной машине или в отдельном
compose-проекте (
COMPOSE_PROJECT_NAME=taimen-restore, свои порты); - восстановите все дампы, выполните шаги полного восстановления;
- сравните число задач, событий журнала, principals, узлов и чанков памяти с боевыми значениями на момент дампа.
Хранение журнала Control Plane¶
Журнал событий растёт вместе с работой. Retention — операторская команда,
планировщика нет: :archive переносит подтверждённую историю в архивную
таблицу той же базы, :prune удаляет физически. Горизонт ограничен
минимальным курсором потребителей, поэтому нужное кому-то не удаляется.
Подробности и команды — в Мониторинге и здоровье и
Событиях Control Plane.
Warning
:prune — единственная операция, после которой данные теряются. Перед
ней должен быть свежий бэкап базы Control Plane.