Kravchenko

Web Lab

АудитБлогКонтакты

Kravchenko

Web Lab

Разрабатываем сайты и автоматизацию на современных фреймворках под ключ

Услуги
ЛендингМногостраничныйВизитка
E-commerceБронированиеПортфолио
Навигация
БлогКонтактыАудит
Обратная связь
+7 921 567-11-16
info@kravlab.ru
с 09:00 до 18:00

© 2026 Все права защищены

•

ИП Кравченко Никита Владимирович

•

ОГРНИП: 324784700339743

Политика конфиденциальности

Бэкапы и восстановление: как уложиться в RPO/RTO и не терять выручку (Postgres, S3, Kubernetes)

Разработка и технологии1 апреля 2026 г.
Бэкапы — это не файлы «на всякий случай», а управляемая система, которая спасает выручку, когда что-то ломается. Разбираем, как задать и выдержать RPO/RTO, что именно бэкапить на уровне БД, объектного хранилища и Kubernetes, как шифровать и проверять целостность, и как регулярно тренировать восстановление. Даём готовые примеры для PostgreSQL (PITR с WAL‑G), S3/MinIO (версионирование, жизненные циклы) и Velero для кластеров.
Бэкапы и восстановление: как уложиться в RPO/RTO и не терять выручку (Postgres, S3, Kubernetes)

Содержание

  • Зачем бизнесу управляемые бэкапы: о чём эта статья
  • Базовые понятия: RPO, RTO, «точки восстановления» и правило 3‑2‑1
  • Что именно бэкапить: уровни — БД, файлы/объекты, конфигурации, инфраструктура
  • PostgreSQL на практике: PITR c WAL‑G, шифрование, проверка восстановления
  • Объектные хранилища S3/MinIO: версионирование, жизненные циклы, целостность
  • Kubernetes: как бэкапить etcd/манифесты/PV с Velero
  • Автоматизация и наблюдаемость: расписания, алерты, метрики
  • Учебные тревоги: как проверять, что восстановление реально работает
  • Сколько это стоит: уровни RPO/RTO и экономика
  • Чек‑лист и частые ошибки

Зачем бизнесу управляемые бэкапы: о чём эта статья

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

  • заранее известны целевые RPO и RTO;
  • бэкапы полностью автоматизированы и наблюдаемы;
  • восстановление регулярно тренируется.

Разберёмся без лишней теории: что означают RPO/RTO на практике, как построить работающую схему для PostgreSQL, S3/MinIO и Kubernetes, как зашифровать и удешевить хранение, и как проверять восстановление «в боевых условиях» — так, чтобы простои не съедали выручку.

Базовые понятия: RPO, RTO, «точки восстановления» и правило 3‑2‑1

  • RPO (Recovery Point Objective) — сколько данных вы готовы потерять при аварии. Пример: RPO=5 минут означает, что максимум 5 минут записей могут исчезнуть.
  • RTO (Recovery Time Objective) — сколько времени вы готовы ждать восстановления сервиса. Пример: RTO=30 минут — через полчаса всё должно работать.
  • Точка восстановления (Restore Point) — момент времени, до которого можно откатить данные.
  • Правило 3‑2‑1 — минимум 3 копии, 2 носителя, 1 копия за пределами основной площадки. Для защиты от пожара, криптошифровальщика, ошибок админов и т. п.

Эти величины надо привязать к деньгам: сколько стоит минута простоя и минута потери данных. Так проще принимать решения о частоте бэкапов, типах хранилищ и автоматизации.

Что именно бэкапить: уровни — БД, файлы/объекты, конфигурации, инфраструктура

  • Данные БД: транзакции, индексы, последовательности — основа отчётов, заказов, платежей.
  • Файлы/объекты: аватарки, документы, вложения — они не в БД, но критичны для клиентов.
  • Конфигурации: переменные окружения, секреты, манифесты, Terraform/Helm чарты — без них восстановление задержится.
  • Инфраструктура: снимки дисков, образы машин, контрольные точки etcd (для Kubernetes).

Важно: бэкап без понятной процедуры восстановления — это не бэкап, а самоуспокоение. Дальше — конкретика.

PostgreSQL на практике: PITR c WAL‑G, шифрование, проверка восстановления

Что выберем и почему

Для Postgres надёжная схема — полные бэкапы + архивирование WAL (журналов транзакций) и восстановление до нужного момента (PITR). Инструменты: WAL‑G или pgBackRest. Возьмём WAL‑G: он простой, быстрый, понимает S3 и шифрование.

Настройка архивации WAL и full‑бэкапов с WAL‑G

Предположим, у нас Postgres 14+, доступ к S3/MinIO с версионированием и ключ шифрования в KMS.

# Устанавливаем wal-g (пример для Debian/Ubuntu)
curl -L https://github.com/wal-g/wal-g/releases/download/v2.0.1/wal-g.linux-amd64.tar.gz | sudo tar -xz -C /usr/local/bin

# Переменные окружения (поместите в /etc/wal-g/env или systemd unit)
export WALG_S3_PREFIX="s3://my-backups/postgres-main"
export AWS_REGION="eu-central-1"
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
export WALG_S3_SSE_KMS_ID="arn:aws:kms:eu-central-1:123456789012:key/abcd-efgh..."  # шифрование на стороне S3/KMS
export WALG_COMPRESSION_METHOD="brotli"
export PGDATA="/var/lib/postgresql/14/main"
export PGPASSWORD="supersecret"
export PGHOST="localhost"
export PGUSER="postgres"

# Включаем archiving в postgresql.conf
# (пример командой; можно отредактировать файл вручную)
psql -U postgres -c "ALTER SYSTEM SET archive_mode = 'on';"
psql -U postgres -c "ALTER SYSTEM SET archive_command = 'wal-g wal-push %p';"
psql -U postgres -c "ALTER SYSTEM SET wal_level = 'replica';"
psql -U postgres -c "SELECT pg_reload_conf();"

# Делаем базовый полный бэкап
wal-g backup-push "$PGDATA"

# Проверяем список бэкапов
wal-g backup-list

Cron для регулярных full и очистки старых:

# /etc/cron.d/pg-backup
# Full бэкап раз в сутки в 02:10
10 2 * * * postgres . /etc/wal-g/env && /usr/local/bin/wal-g backup-push /var/lib/postgresql/14/main >> /var/log/wal-g.log 2>&1
# Тримминг старых бэкапов: храним 7 штук
30 3 * * * postgres . /etc/wal-g/env && /usr/local/bin/wal-g delete retain FULL 7 --confirm >> /var/log/wal-g.log 2>&1

Важно: архивирование WAL идёт постоянно через archive_command — это даёт RPO в минуты.

Восстановление до точки во времени (PITR)

Процедура на «чистой» машине:

# Останавливаем Postgres и чистим PGDATA
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/14/main/*

# Восстанавливаем последнюю базу
sudo -u postgres env -i bash -c '
  source /etc/wal-g/env
  /usr/local/bin/wal-g backup-fetch /var/lib/postgresql/14/main LATEST
'

# Указываем желаемое время (или метку) в recovery.signal
# Для Postgres 12+ используется параметр в postgresql.auto.conf или файл recovery.signal
sudo -u postgres bash -c "echo "restore_command = 'wal-g wal-fetch %f %p'" >> /var/lib/postgresql/14/main/postgresql.auto.conf"

# Восстановление, например, на момент за 2 минуты до инцидента
sudo -u postgres bash -c "echo "recovery_target_time = '2026-03-30 12:15:00+00'" >> /var/lib/postgresql/14/main/postgresql.auto.conf"

sudo systemctl start postgresql

Проверяйте: правильные пользователи/расширения, последовательности не «убежали», отчёты сходятся.

Шифрование и доступ

  • Шифруем на уровне S3 (SSE‑KMS) или в клиенте (WAL‑G поддерживает). Ключи храним в KMS, доступ — по ролям с минимальными правами.
  • Для критичных данных включите «неизменяемость» (Object Lock/WORM) на период, чтобы бэкапы нельзя было стереть при компрометации учётки.

Автотест восстановления

Скрипт, который разворачивает временный Postgres, восстанавливает «вчерашний» бэкап и гоняет SQL‑проверки. Запускайте по расписанию.

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

WHEN=$(date -u -d "yesterday" +"%Y-%m-%d 03:00:00+00")
TMP=/var/lib/postgresql/restore-check

systemctl stop postgresql || true
rm -rf "$TMP" && mkdir -p "$TMP"

# Восстанавливаем в TMP
sudo -u postgres env -i bash -c '
  source /etc/wal-g/env
  export PGDATA="'$TMP'"
  /usr/local/bin/wal-g backup-fetch "$PGDATA" LATEST
  echo "restore_command = 'wal-g wal-fetch %f %p'" >> "$PGDATA"/postgresql.auto.conf
  echo "recovery_target_time = '"'$WHEN'"'" >> "$PGDATA"/postgresql.auto.conf
  pg_ctl -D "$PGDATA" -o "-p 55432" start
'

# Простая проверка
sleep 5
psql -h localhost -p 55432 -U postgres -c "SELECT current_database(), now();"

# Бизнес-проверки: есть ли вчерашние заказы
psql -h localhost -p 55432 -U postgres -d app -c "SELECT count(*) FROM orders WHERE created_at::date = (CURRENT_DATE - 1);"

# Остановка тестового инстанса
sudo -u postgres pg_ctl -D "$TMP" stop
rm -rf "$TMP"
echo "restore check ok"

Объектные хранилища S3/MinIO: версионирование, жизненные циклы, целостность

Если вы храните пользовательские файлы в S3/MinIO, «бэкап» — это правильно настроенное ведро (bucket): включённое версионирование, правила жизненного цикла, возможно — репликация в другой регион/аккаунт.

Terraform: ведро с версионированием, WORM и жизненным циклом

# Пример для AWS S3
provider "aws" {
  region = "eu-central-1"
}

resource "aws_s3_bucket" "files" {
  bucket = "myapp-prod-files"
  force_destroy = false
}

resource "aws_s3_bucket_versioning" "files" {
  bucket = aws_s3_bucket.files.id
  versioning_configuration {
    status = "Enabled"
  }
}

# Object Lock (WORM) — требует создание ведра со включенным lock заранее!
resource "aws_s3_bucket_object_lock_configuration" "files" {
  bucket = aws_s3_bucket.files.id
  rule {
    default_retention {
      mode  = "COMPLIANCE"
      days  = 7
    }
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "files" {
  bucket = aws_s3_bucket.files.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = "arn:aws:kms:eu-central-1:123456789012:key/abcd-efgh..."
    }
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "files" {
  bucket = aws_s3_bucket.files.id

  rule {
    id     = "noncurrent-to-glacier"
    status = "Enabled"

    noncurrent_version_transition {
      noncurrent_days = 30
      storage_class   = "GLACIER"
    }

    noncurrent_version_expiration {
      noncurrent_days = 365
    }
  }
}

Целостность и восстановление

  • При загрузке сохраняйте и проверяйте контрольные суммы (ETag/MD5 или SHA‑256 в метаданных).
  • Храните карту «имя объекта → версия», чтобы вернуть файл, который удалил пользователь.
  • Тест восстановления: раз в неделю поднимайте тестовый бакет, копируйте N случайных версий, сравнивайте хэши.

Пример скрипта проверки последних бэкапов и метрики для Prometheus (через текстовый экспорт):

#!/usr/bin/env bash
# s3_backup_age.sh — выводит возраст последнего бэкапа в секундах
set -euo pipefail
BUCKET="my-backups"
PREFIX="postgres-main/basebackups_005"
OUT="/var/lib/node_exporter/textfile_collector/backup_age.prom"

LATEST=$(aws s3api list-objects-v2 --bucket "$BUCKET" --prefix "$PREFIX" --query 'reverse(sort_by(Contents,&LastModified))[:1].LastModified' --output text)
if [ "$LATEST" = "None" ]; then
  echo "backup_age_seconds -1" > "$OUT"
  exit 1
fi
TS=$(date -d "$LATEST" +%s)
NOW=$(date +%s)
AGE=$((NOW-TS))
echo "backup_age_seconds $AGE" > "$OUT"

Заведите алерт: если backup_age_seconds > 36 часов — тревога.

Kubernetes: как бэкапить etcd/манифесты/PV с Velero

В Kubernetes «приложение» — это манифесты + секреты + тома (PersistentVolume). Удобный инструмент — Velero: снимает «снимки» объектов API и может бэкапить тома через плагины.

Установка Velero и базовый бэкап

# Установка в кластер (пример c AWS и S3)
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.8.0 \
  --bucket my-k8s-backups \
  --secret-file ./credentials-velero \
  --backup-location-config region=eu-central-1,s3ForcePathStyle=true,s3Url=https://s3.eu-central-1.amazonaws.com \
  --snapshot-location-config region=eu-central-1

# Создать ежедневный бэкап всего неймспейса prod, хранить 14 дней
kubectl apply -f - <<'YAML'
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-prod
  namespace: velero
spec:
  schedule: "0 3 * * *"
  template:
    includedNamespaces:
      - prod
    storageLocation: default
    ttl: 336h # 14 дней
YAML

Проверка восстановления на «чистый» кластер

  • Поднимите временный кластер (kind/k3s), поставьте Velero, укажите тот же бакет.
  • Выполните восстановление:
velero restore create --from-backup daily-prod-20260330 --wait
  • Проверьте поды, секреты и PVC. Для стейтфул‑сервисов (например, Postgres в кластере) лучше сочетать: БД восстанавливать PITR‑процедурой, а Kubernetes‑объекты — через Velero.

Автоматизация и наблюдаемость: расписания, алерты, метрики

  • Расписания: cron/CI для БД, Velero Schedule для K8s, lifecycle в S3.
  • Метрики: возраст последнего full‑бэкапа, задержка WAL, успешность тестового восстановления, длительность restore (сравниваем с RTO).
  • Логи: отдельный индекс/папка для «backup‑» и «restore‑» событий, чтобы не теряться в шуме.
  • Алерты: «нет нового бэкапа > N часов», «restore‑тест не прошёл за последние M дней», «объём бакета вырос > X% за неделю» (сигнал о сломанных политиках удаления).

Учебные тревоги: как проверять, что восстановление реально работает

Минимум раз в месяц проводите «пожарную тренировку»:

  • Выбираем сценарий: потеря части данных, массовое удаление, компрометация доступа.
  • На изолированной площадке: сворачиваем «как в бою»: создаём инфраструктуру, восстанавливаем БД до метки, докатываем объекты из S3, разворачиваем Kubernetes‑манифесты.
  • Сверяем контрольные точки: бизнес‑метрики за день/неделю, согласованность отчётов, работоспособность API.
  • Фиксируем фактические RPO и RTO. Если хуже целевых — дорабатываем.

Полезно: хранить чек‑листы и «шпаргалки» (runbook) в репозитории рядом с кодом.

Сколько это стоит: уровни RPO/RTO и экономика

  • RPO ~ 24 часа, RTO ~ 24 часа: дешёво (ежедневные бэкапы, холодное хранилище), но потери в данные и простой большие — годится для несрочных сервисов.
  • RPO ~ 5–15 минут, RTO ~ 1–2 часа: золотая середина для B2B: WAL‑архивирование, ежедневные full, автоматизированные restore‑тесты, версионирование S3, Velero для K8s.
  • RPO ~ 0–1 минута, RTO ~ минуты: дорого — синхронная репликация в другой AZ/регион, горячий standby, immutable‑бэкапы. Настоящий «почти ноль простоев» для критичных платёжных/операционных систем.

Оптимизировать расходы помогают: хранение инкрементальных бэкапов, перевод старых версий в «холодные» классы (Glacier/архив), дедупликация, сжатие (brotli/zstd), агрессивные политики удаления тестовых окружений после restore‑тренировок.

Чек‑лист и частые ошибки

Чек‑лист:

  • Определены и подписаны целевые RPO/RTO по доменам данных.
  • Есть минимум 3‑2‑1 копии, одна — вне основной площадки/аккаунта.
  • Бэкапы шифруются (KMS), есть политика ротации ключей.
  • Включены версионирование объектов и политики жизненного цикла.
  • Настроены регулярные restore‑тесты с измерением времени и проверками бизнес‑метрик.
  • Метрики и алерты на «возраст бэкапа», «успешность restore», «рост хранилища».
  • Документированы и оттестированы процедурные шаги (runbook), доступные on‑call.

Частые ошибки:

  • «Есть бэкап, значит всё хорошо»: без регулярных восстановлений уверенности нет.
  • Только дамп БД без WAL: RPO становится «как повезёт», обычно сутки.
  • Бэкапы в том же аккаунте и без Object Lock: одно неудачное удаление — и вы без истории.
  • Бэкапят только БД, забывая про файлы/секреты — восстановление упирается в «а переменные окружения где?».
  • Нет контроля ключей и аудита доступа к бакету: риск утечки и шифровальщиков.

Итог

Бэкап — это сервис, а не папка с файлами. Сформулируйте RPO/RTO на языке денег, постройте схему «Postgres PITR + версионированный S3 + Velero для K8s», включите шифрование и неизменяемость, автоматизируйте проверки восстановления и заведите метрики. Тогда любая авария превратится в понятную процедуру с прогнозируемым временем и стоимостью — без сюрпризов для клиентов и выручки.


PostgreSQLбэкапыRPO/RTO