Резервное копирование
Что копировать в on-prem-установке ActionPulse, какие средства входят в комплект, как проверить, что копия действительно восстанавливается, и что в неё не попадает.
На этой странице
Состояние установки ActionPulse лежит в нескольких независимых хранилищах, и потеря каждого стоит разного. Комплект поставки содержит готовый раннер полного копирования PostgreSQL и ClickHouse в S3-совместимое хранилище с подписанным манифестом и периодической проверкой восстановлением. Всё остальное — секреты, транспорт, наблюдаемость — в этот снимок не входит и требует вашего собственного решения.
Что именно надо копировать
| Хранилище | Что в нём | Что теряется без него |
|---|---|---|
PostgreSQL (том pg-data) |
пользователи, организации и проекты, роли, ключи, отчёты, сегменты, панели, оповещения, импорты, задачи и журнал удаления данных, запись лицензии, журналы миграций | вся конфигурация установки. События в ClickHouse остаются, но их не к чему привязать: проектов, ключей и прав больше нет |
ClickHouse (том ch-data) |
события, аналитические таблицы и материализации, фрагменты записанных сессий | вся история продуктовой аналитики |
NATS JetStream (том nats-data) |
транспортные потоки EVENTS, REPLAY, IMPORT_FENCES |
события, принятые но ещё не записанные в ClickHouse. Ретеншн EVENTS — 48 часов, REPLAY — 24 часа: старше этого в транспорте ничего нет |
Redis (том redis-data) |
кэш связок личности, квот и дедупликации | сами данные не теряются, кэш перестраивается. Но при восстановлении Redis обязательно сбрасывается — см. Восстановление |
Том import-uploads |
загруженные CSV незавершённых импортов | незавершённый импорт нельзя продолжить, файл придётся загрузить заново. Чекпоинт и история сопоставления остаются в PostgreSQL |
.env, каталог secrets/, TLS-ключи, ключ лицензии |
секреты, конфигурация, ключи шифрования | установка не поднимается, а часть данных в PostgreSQL перестаёт читаться навсегда |
Том caddy-data |
сертификаты и состояние ACME | для реального домена сертификат будет выпущен заново; на время выпуска сайт недоступен по HTTPS |
| Тома Prometheus, Elasticsearch, Grafana, Kibana | метрики, журналы, панели | наблюдаемость за прошедший период. На работу продукта не влияет |
Что есть в комплекте
Раннер копирования включается отдельным профилем Compose. Он не запускается
обычным up -d — сначала настраивается хранилище, потом включается профиль.
docker compose -f docker-compose.onprem.yml --env-file .env --profile backup up -d
| Сервис | Что делает |
|---|---|
backup |
последовательный планировщик: снимает полные копии PostgreSQL и ClickHouse и публикует подписанный манифест. Единственный контейнер, получающий приватный ключ подписи |
backup-verify |
периодическое изолированное восстановление последнего снимка в отдельные, выбрасываемые базы. Держит только публичные ключи проверки |
backup-init |
одноразовая подготовка томов (владелец и права). Запускается и без профиля backup |
Исполняемые файлы раннера — backup.sh, restore.sh, verify.sh, prune.sh,
scheduler.sh и утилита apbackupctl — лежат внутри образа, закреплённого
по digest, в каталоге /opt/actionpulse-backup/. В комплект они отдельными
файлами не входят, и собирать образ не нужно: он приезжает готовым.
В каталоге backup/ комплекта лежат ровно три файла:
clickhouse-named-collection.xml— именованная коллекция, которую Compose монтирует в ClickHouse: через неё сервер сам пишет свой бэкап в S3, а учётные данные берутся из окружения процесса и не попадают ни в SQL, ни в журнал запросов;.env.example— перечень переменных раннера с пояснениями;README.md— модель безопасности, контракт манифеста и согласованность между хранилищами.
Настройка
Переменные задаются в .env комплекта. Значений здесь нет намеренно: секреты
генерируйте свои, адреса и имена — свои.
| Переменная | Назначение | Обязательность |
|---|---|---|
BACKUP_S3_BUCKET |
бакет для копий | обязательна |
BACKUP_S3_PREFIX |
префикс внутри бакета, отдельный для этой установки | необязательна |
BACKUP_S3_REGION |
регион | необязательна |
BACKUP_S3_ENDPOINT |
HTTPS-адрес S3-совместимого хранилища; пусто — AWS | необязательна |
BACKUP_S3_SSE_MODE |
режим шифрования на стороне хранилища | необязательна |
BACKUP_S3_KMS_KEY_ID |
полный ARN ключа при режиме aws:kms |
обязательна для KMS |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY |
доступ принципала к бакету — сгенерируйте свои | обязательны |
BACKUP_CH_S3_URL |
базовый адрес для серверного бэкапа ClickHouse; заканчивается на /clickhouse/ внутри вашего префикса |
обязательна |
BACKUP_MANIFEST_SIGNING_KEY |
приватный ключ подписи манифеста — сгенерируйте свой | обязательна |
BACKUP_MANIFEST_PUBLIC_KEYS |
список публичных ключей проверки через запятую | обязательна |
BACKUP_INSTALLATION_ID |
устойчивый идентификатор инсталляции: не даёт применить журнал удалений чужой установки | необязательна |
BACKUP_INTERVAL_SECONDS |
период планировщика | необязательна |
BACKUP_RETENTION_DAYS |
срок хранения снимков | необязательна |
BACKUP_MIN_COMPLETE_SNAPSHOTS |
сколько полных снимков не удалять никогда | необязательна |
BACKUP_RPO_SECONDS, BACKUP_RTO_SECONDS |
ваши цели по потере данных и времени восстановления, попадают в метрики | необязательны |
BACKUP_CH_HASH_MODE |
полное хеширование объектов ClickHouse | необязательна |
BACKUP_ABORT_MULTIPART_AFTER_DAYS |
через сколько прерывать незавершённые многочастевые загрузки | необязательна |
BACKUP_PRUNE_DRY_RUN |
холостой прогон удаления по сроку хранения | необязательна |
VERIFY_INTERVAL_SECONDS |
период изолированной проверки восстановлением | необязательна |
Пару ключей подписи манифеста создаёт утилита из того же образа:
docker run --rm --entrypoint /opt/actionpulse-backup/apbackupctl \
"$PP_BACKUP_IMAGE_REF" keygen -key-id 2026-07
Требования к хранилищу, которые проверяются fail-closed:
- принципал должен иметь ровно
ListBucket,GetBucketLocation,PutObject,GetObject,HeadObject,DeleteObject,ListBucketMultipartUploads,AbortMultipartUpload; для KMS — толькоEncrypt,Decrypt,GenerateDataKeyна одном ключе; - шифрование бакета по умолчанию должно быть включено и совпадать с
BACKUP_S3_SSE_MODE; проверка выполняется и до, и после загрузки; - адрес хранилища — HTTPS, соединения с PostgreSQL и ClickHouse — по TLS. Незашифрованные режимы требуют явных небезопасных флагов и существуют только для локального изолированного прогона;
- в правилах жизненного цикла бакета для вашего префикса отдельно настраиваются
прерывание незавершённых загрузок, удаление неактуальных версий и маркеров
удаления только после истечения срока соответствия, и срок истечения не
короче
BACKUP_RETENTION_DAYS. При включённом Object Lock жизненный цикл обязан дожидатьсяretain-until, а у принципала копирования не должно быть права обходить блокировку.
Что такое снимок
Один снимок — это три группы объектов под вашим префиксом:
<prefix>/postgresql/<snapshot>.dump логический дамп PostgreSQL
<prefix>/clickhouse/<snapshot>/... нативный полный бэкап ClickHouse
<prefix>/manifests/<snapshot>.json подписанный манифест, публикуется последним
Манифест — точка доверия. Он подписан Ed25519 (схема 2; неподписанная схема 1 отвергается) и фиксирует идентификатор набора и снимка, время начала и завершения, бакет, префикс и режим шифрования, версии схем PostgreSQL и ClickHouse, водяной знак согласованности и каждый объект с его размером и SHA-256. Полное хеширование объектов ClickHouse — единственное, что обнаруживает подмену объекта под неизменившимся именем; оно стоит одного дополнительного чтения за прогон, и режим «только метаданные» на входе запрещён.
Копирование ClickHouse — всегда полное, без инкрементных цепочек. Это дороже по объёму и вводу-выводу, зато удаление одного снимка по сроку хранения не делает непригодными остальные.
Частота и хранение
По умолчанию планировщик снимает копию раз в сутки, снимки хранятся 30 дней и никогда не удаляется меньше двух полных. Удаление по сроку хранения идёт в безопасном порядке: сначала объекты ClickHouse, затем дамп PostgreSQL, манифест — последним, поэтому прерванное удаление не оставляет «манифест без данных».
Цели по допустимой потере данных и по времени восстановления — ваша конфигурация, а не обещание ActionPulse. Поставляемые значения по умолчанию — только стартовая точка: согласуйте их с объёмом, стоимостью и вашими бизнес-требованиями, а затем измерьте учебным восстановлением. До измерения это не цели, а предположения.
Проверка, что копия рабочая
Копия, которую ни разу не восстанавливали, копией не является: до первого восстановления неизвестно ни время восстановления, ни то, хватает ли прав на чтение объектов, ни доступен ли ключ проверки манифеста.
Автоматически. Сервис backup-verify берёт последний полный снимок,
проверяет подпись манифеста, пересоздаёт выбрасываемые базы и восстанавливает
снимок в них — по умолчанию раз в сутки. Живые базы он не трогает: сценарий
восстановления отказывается работать «на месте». Результат попадает в метрики
pp_backup_restore_*.
Метрики. Раннер атомарно пишет текстовый файл метрик, который читает
node-exporter. Единственная метка — component со значением postgresql или
clickhouse; ни текста ошибки, ни идентификатора снимка, ни имён объектов в
метках нет.
pp_backup_last_attempt_timestamp_seconds pp_backup_restore_last_attempt_timestamp_seconds
pp_backup_last_success_timestamp_seconds pp_backup_restore_last_success_timestamp_seconds
pp_backup_last_duration_seconds pp_backup_restore_last_duration_seconds
pp_backup_last_status pp_backup_restore_last_status
pp_backup_consecutive_failures pp_backup_rto_target_seconds
pp_backup_rpo_target_seconds
Признак успеха строгий: pp_backup_last_status становится 1 только после
загрузки, проверки размера и статуса объекта в хранилище, проверки шифрования и
публикации полного манифеста. Любой сбой до манифеста оставляет 0, увеличивает
счётчик последовательных отказов и завершает прогон с ошибкой. Отказ удаления по
сроку уже после успешного манифеста подтверждённый снимок не аннулирует.
Фактическое отставание копии проверяется одним запросом — для обоих компонентов результат должен быть не больше цели:
time() - pp_backup_last_success_timestamp_seconds
Правила оповещений для этого уже есть в комплекте:
ActionPulseBackupFailed, ActionPulseBackupRPOExceeded и
ActionPulseBackupTelemetryMissing — последнее срабатывает, когда метрик нет
вовсе, то есть когда раннер молча не работает.
Руками. Изолированное восстановление проводят не реже раза в квартал и обязательно перед опасным крупным обновлением. Порядок и проверки — на странице Восстановление из резервной копии. Записывайте фактические количества строк, контрольные суммы, время начала и конца и измеренное время восстановления: это и есть ваш план восстановления.
Что не входит в копию
- NATS JetStream. Транспорт не часть снимка баз. Его ретеншн ограничен: 48 часов для потока событий и 24 часа для потока сессий. Снимок тома и экспорт конфигурации потоков и потребителей — отдельная процедура, и перед обновлением она обязательна.
.env, каталогsecrets/, TLS-сертификаты и ключи,LICENSE_PUBKEY, материал KMS, ключ вебхуков. Их намеренно не кладут рядом с данными: хранилище копий данных не должно давать доступ к ключам, которыми эти данные зашифрованы.- Ключ лицензии как файл. Запись о лицензии есть в PostgreSQL и приезжает с дампом, но конфигурация установки — нет. После восстановления статус лицензии проверяют отдельно.
- Redis. Это кэш; более того, при восстановлении «на месте» он принудительно очищается.
- Том
import-uploads. Сырые загруженные CSV в снимок не попадают. - Тома наблюдаемости — Prometheus, Elasticsearch, Grafana, Kibana.
- Сертификаты Caddy (том
caddy-data). - База GeoIP. Её поставляете вы, в комплект она не входит.
Согласованность между хранилищами
PostgreSQL и ClickHouse не снимаются одной распределённой транзакцией. Вместо
этого манифест фиксирует явный барьер записи: consistency.watermark_at берётся
непосредственно перед тем, как дамп PostgreSQL получает свой снимок. Оба
хранилища гарантированно содержат всё, что записано до этого момента.
Копирование ClickHouse завершается позже, поэтому в нём есть события, о которых восстановленный контроль-план ничего не знает. При восстановлении сценарий удаляет из аналитических событий строки новее водяного знака — и оба хранилища оказываются в одной точке времени.
Одно исключение записано в самом манифесте: фрагменты записанных сессий не имеют серверной отметки времени, поэтому за барьером может остаться до (конец копирования ClickHouse − водяной знак) таких данных. Окно ограничено и зафиксировано в манифесте.
Отдельно живёт подписанный журнал удалений тенантов. Неизменяемое хранилище не
умеет «забыть» удалённую организацию по требованию — байты остаются до истечения
снимка. Поэтому каждое восстановление проигрывает записи журнала в
восстановленные базы, прежде чем данные становятся доступны. Это логическое
стирание в момент восстановления, а не физическое стирание внутри хранимых
снимков: физически данные исчезают, когда удаляется последний снимок, их
содержащий, — то есть не позже BACKUP_RETENTION_DAYS после удаления плюс
любые сроки Object Lock и хранения неактуальных версий на стороне провайдера.
Не обещайте своим пользователям срок короче того, который реально обеспечивает
политика вашего бакета.
Что проверить прямо сейчас
pp_backup_last_success_timestamp_secondsобновлялся не позже вашей цели — для обоих компонентов.pp_backup_restore_last_statusравен1: изолированное восстановление действительно проходило, а не только копирование.- В бакете есть не меньше двух манифестов со состоянием «полный».
- Публичный ключ проверки манифеста доступен там, откуда вы будете восстанавливаться, — и это не только этот сервер.
- Секреты установки (
.env,secrets/, TLS-ключи) лежат в вашем менеджере секретов и не в бакете копий. - Дата последнего учебного восстановления вручную — не старше квартала.