О нас Руководства Проекты Контакты
Админка
пожалуйста подождите

Постановка задачи

Необходимо защитить системы от потери данных, минимизировать простои во время аварий и обеспечить непрерывность бизнеса за счёт проверенных процедур восстановления.

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

МетрикаОпределениеТипичные целевые значения
RPO (Recovery Point Objective)Максимально допустимая потеря данных0–24 часа
RTO (Recovery Time Objective)Максимально допустимый простойМинуты–часы

Архитектура резервного копирования

┌─────────────────────────────────────────────────────────────────────────┐
│ Production Environment │
├────────────────┬────────────────┬────────────────┬─────────────────────┤
│ Kubernetes │ Database │ Object Store │ Configuration │
│ Workloads │ (Primary) │ (S3/MinIO) │ (GitOps Repo) │
└───────┬────────┴───────┬────────┴───────┬────────┴─────────┬───────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌───────────────────────────────────────────────────────────────────────┐
│ Backup Layer │
├────────────────┬────────────────┬────────────────┬────────────────────┤
│ Velero │ pg_dump / │ S3 Cross- │ Git Mirror │
│ Snapshots │ mysqldump │ Region │ │
└───────┬────────┴───────┬────────┴───────┬────────┴────────┬───────────┘
│ │ │ │
└────────────────┴────────────────┴──────────────────┘
│
┌───────────▼───────────┐
│ Offsite Backup │
│ Storage (S3/GCS) │
│ Different Region │
└───────────────────────┘

1. Резервное копирование Kubernetes с Velero

Установка Velero

# Установить Velero CLI
wget https://github.com/vmware-tanzu/velero/releases/download/v1.12.0/velero-v1.12.0-linux-amd64.tar.gz
tar -xvf velero-v1.12.0-linux-amd64.tar.gz
mv velero-v1.12.0-linux-amd64/velero /usr/local/bin/
# Установить Velero в кластере
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket velero-backups \
--secret-file ./credentials-velero \
--backup-location-config region=us-west-2,s3ForcePathStyle="true",s3Url=https://s3.us-west-2.amazonaws.com \
--snapshot-location-config region=us-west-2

credentials-velero

[default]
aws_access_key_id=YOUR_ACCESS_KEY
aws_secret_access_key=YOUR_SECRET_KEY

Расписания резервного копирования

apiVersion: velero.io/v1
kind: Schedule
metadata:
name: daily-backup
namespace: velero
spec:
schedule: "0 2 * * *" # Ежедневно в 2:00
template:
includedNamespaces:
- production
- staging
excludedResources:
- events
- pods
storageLocation: default
ttl: 720h # Хранение 30 дней
snapshotVolumes: true
volumeSnapshotLocations:
- default
---
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: hourly-backup
namespace: velero
spec:
schedule: "0 * * * *" # Каждый час
template:
includedNamespaces:
- production
includedResources:
- configmaps
- secrets
- deployments
- services
- ingresses
ttl: 168h # Хранение 7 дней
snapshotVolumes: false

Ручное резервное копирование

# Создать резервную копию всех production-ресурсов
velero backup create production-backup-$(date +%Y%m%d) \
--include-namespaces production \
--snapshot-volumes
# Создать резервную копию перед крупными изменениями
velero backup create pre-migration-backup \
--include-namespaces production \
--wait

Восстановление из резервной копии

# Список резервных копий
velero backup get
# Восстановить в тот же кластер
velero restore create --from-backup production-backup-20240115 \
--include-namespaces production
# Восстановить в другое namespace (для тестирования)
velero restore create --from-backup production-backup-20240115 \
--namespace-mappings production:restore-test

2. Стратегии резервного копирования баз данных

Непрерывное архивирование PostgreSQL (WAL)

# postgresql.conf
archive_mode = on
archive_command = 'aws s3 cp %p s3://db-backups/wal/%f'
wal_level = replica
# Скрипт базовой резервной копии
##!/bin/bash
BACKUP_NAME="base-$(date +%Y%m%d_%H%M%S)"
pg_basebackup -D /tmp/$BACKUP_NAME -Ft -z -Xs -P
aws s3 cp /tmp/$BACKUP_NAME.tar.gz s3://db-backups/base/$BACKUP_NAME.tar.gz
rm -rf /tmp/$BACKUP_NAME*

Резервное копирование PostgreSQL с pgBackRest

# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/backup/pgbackrest
repo1-retention-full=2
repo1-retention-diff=14
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=your-encryption-key
[main]
pg1-path=/var/lib/pgsql/data
# Полная резервная копия (еженедельно)
pgbackrest --stanza=main backup --type=full
# Дифференциальная резервная копия (ежедневно)
pgbackrest --stanza=main backup --type=diff
# Восстановление до заданного момента времени (point-in-time recovery)
pgbackrest --stanza=main restore \
--type=time \
--target="2024-01-15 10:30:00"

Резервное копирование MySQL/Percona с Percona XtraBackup

# Полная резервная копия
xtrabackup --backup --target-dir=/backup/full/$(date +%Y%m%d)
# Инкрементальная резервная копия
xtrabackup --backup --target-dir=/backup/incr/$(date +%Y%m%d) \
--incremental-basedir=/backup/full/20240115
# Подготовка к восстановлению
xtrabackup --prepare --target-dir=/backup/full/20240115
xtrabackup --prepare --target-dir=/backup/full/20240115 \
--incremental-dir=/backup/incr/20240116
# Восстановление
systemctl stop mysql
rm -rf /var/lib/mysql/*
xtrabackup --copy-back --target-dir=/backup/full/20240115
chown -R mysql:mysql /var/lib/mysql
systemctl start mysql

Kubernetes CronJob для резервного копирования базы данных

apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
namespace: production
spec:
schedule: "0 3 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: postgres:15
command:
- /bin/bash
- -c
- |
set -e
BACKUP_NAME="backup-$(date +%Y%m%d-%H%M%S).sql.gz"
pg_dump -h $DB_HOST -U $DB_USER $DB_NAME | gzip > /tmp/$BACKUP_NAME
aws s3 cp /tmp/$BACKUP_NAME s3://db-backups/postgres/$BACKUP_NAME
# Очистка старых резервных копий (оставить последние 30)
aws s3 ls s3://db-backups/postgres/ | sort -r | tail -n +31 | \
awk '{print $4}' | xargs -I {} aws s3 rm s3://db-backups/postgres/{}
env:
- name: DB_HOST
value: postgres-service
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_NAME
value: production
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-credentials
key: access-key
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-credentials
key: secret-key

3. Аварийное восстановление в нескольких регионах

Схема Active-Passive

# Основной регион
apiVersion: v1
kind: Service
metadata:
name: app-primary
annotations:
external-dns.alpha.kubernetes.io/hostname: app.example.com
external-dns.alpha.kubernetes.io/ttl: "60"
spec:
type: LoadBalancer
selector:
app: myapp
---
# Вторичный регион (standby)
apiVersion: v1
kind: Service
metadata:
name: app-secondary
annotations:
# DNS-запись активируется только во время failover
external-dns.alpha.kubernetes.io/hostname: app-dr.example.com
spec:
type: LoadBalancer
selector:
app: myapp

Репликация базы данных между регионами

# CloudNativePG Cross-Region Replica
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres-replica
namespace: production
spec:
instances: 2
replica:
enabled: true
source: postgres-primary
externalClusters:
- name: postgres-primary
connectionParameters:
host: postgres-primary.us-west-2.rds.amazonaws.com
user: replicator
password:
name: replication-credentials
key: password

4. Верификация и тестирование резервных копий

Автоматизированное тестирование восстановления

apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-verification
spec:
schedule: "0 6 * * 0" # Еженедельно по воскресеньям
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: verify
image: backup-verifier:latest
command:
- /bin/bash
- -c
- |
set -e
# Получить последнюю резервную копию
LATEST=$(aws s3 ls s3://db-backups/postgres/ | sort -r | head -1 | awk '{print $4}')
# Скачать и восстановить в тестовую базу данных
aws s3 cp s3://db-backups/postgres/$LATEST /tmp/backup.sql.gz
gunzip /tmp/backup.sql.gz
# Создать тестовую базу данных
psql -h $TEST_DB_HOST -U $DB_USER -c "DROP DATABASE IF EXISTS backup_test"
psql -h $TEST_DB_HOST -U $DB_USER -c "CREATE DATABASE backup_test"
psql -h $TEST_DB_HOST -U $DB_USER -d backup_test -f /tmp/backup.sql
# Запустить проверочные запросы
USERS=$(psql -h $TEST_DB_HOST -U $DB_USER -d backup_test -t -c "SELECT COUNT(*) FROM users")
ORDERS=$(psql -h $TEST_DB_HOST -U $DB_USER -d backup_test -t -c "SELECT COUNT(*) FROM orders")
# Проверить целостность данных
if [ "$USERS" -gt 0 ] && [ "$ORDERS" -gt 0 ]; then
echo "Backup verification PASSED"
curl -X POST $SLACK_WEBHOOK -d '{"text":"✅ Weekly backup verification passed"}'
else
echo "Backup verification FAILED"
curl -X POST $SLACK_WEBHOOK -d '{"text":"❌ Weekly backup verification FAILED"}'
exit 1
fi
# Очистка
psql -h $TEST_DB_HOST -U $DB_USER -c "DROP DATABASE backup_test"

5. Runbook аварийного восстановления

Чек-лист активации DR

## Disaster Recovery Activation
### Pre-Activation (Assess)
- [ ] Confirm primary site is unavailable
- [ ] Estimate time to recover primary
- [ ] Get management approval for failover
- [ ] Notify stakeholders
### Activation (Execute)
1. [ ] Verify DR site health
```bash
kubectl get nodes
kubectl get pods -A
```
2. [ ] Activate database replica
```bash
# Promote PostgreSQL replica
kubectl exec -it postgres-0 -- pg_ctl promote
```
3. [ ] Update DNS records
```bash
# Point traffic to DR site
aws route53 change-resource-record-sets ...
```
4. [ ] Verify application connectivity
```bash
curl -I https://app.example.com/health
```
5. [ ] Monitor for errors
```bash
kubectl logs -f deployment/myapp
```
### Post-Activation (Verify)
- [ ] Verify all services operational
- [ ] Check database consistency
- [ ] Monitor error rates
- [ ] Communicate status to stakeholders
- [ ] Document timeline and actions taken
### Failback (Return to Primary)
- [ ] Restore primary site
- [ ] Sync data from DR to primary
- [ ] Test primary site
- [ ] Switch traffic back
- [ ] Deactivate DR site

6. Шифрование и безопасность резервных копий

Шифрование резервных копий «на хранении» (at rest)

# Использование GPG для шифрования резервных копий
pg_dump mydb | gpg --encrypt --recipient [email protected] > backup.sql.gpg
# Использование OpenSSL
pg_dump mydb | openssl enc -aes-256-cbc -salt -pass file:/path/to/keyfile > backup.sql.enc
# Расшифровать
openssl enc -d -aes-256-cbc -pass file:/path/to/keyfile < backup.sql.enc | psql mydb

Политика S3 bucket

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceEncryption",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::db-backups/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "RestrictAccess",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::db-backups",
"arn:aws:s3:::db-backups/*"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["10.0.0.0/8"]
}
}
}
]
}

Мышление Senior в DR

Проблема etcd: резервные копии состояния кластера

Состояние вашего Kubernetes-кластера хранится в etcd. Если etcd выйдет из строя и у вас нет резервной копии, вам придётся пересоздавать весь кластер с нуля.

Зашифрованные резервные копии etcd:

# Создать зашифрованную резервную копию
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key
# Зашифровать и загрузить
gpg --encrypt --recipient [email protected] /backup/etcd-*.db
aws s3 cp /backup/etcd-*.db.gpg s3://cluster-backups/etcd/

Планируйте это как минимум ежедневно. Устаревшая резервная копия etcd лучше, чем отсутствие резервной копии.

Философия тестирования: непроверенные резервные копии бесполезны

Правило Senior: резервная копия, которую вы не тестировали, — это не резервная копия, а надежда.

Что тестировать: 1. Можно ли скачать резервную копию? (Сеть, права доступа, ключи шифрования) 2. Можно ли восстановить резервную копию? (Формат, повреждения, полнота) 3. Корректны ли данные? (Количество строк, checksums, тесты приложения) 4. Сколько времени занимает восстановление? (Укладывается ли в ваш RTO?)

Запланируйте автоматизированные тесты восстановления еженедельно. Если тест не проходит, кто-то должен получить оповещение (pager).

Фреймворк принятия решения о failover

Failover — это дорого и рискованно. Используйте этот фреймворк:

ВопросЕсли даЕсли нет
Основная площадка полностью недоступна?Переходите к следующемуЖдите и наблюдайте
Восстановление займёт больше, чем RTO?Переходите к следующемуЖдите и восстанавливайте
Данные на DR-площадке актуальны (в пределах RPO)?Выполняйте failoverОцените риск потери данных
Стейкхолдеры одобряют потерю данных?Выполняйте failoverЖдите или ищите альтернативы

Никогда не выполняйте failover без явного одобрения. Человек, принимающий решение, должен понимать последствия потери данных.

Failback: забытая половина

Планирование failover без планирования failback оставляет вас в режиме DR на неопределённый срок.

Соображения по failback:

  • Как синхронизировать данные обратно на основную площадку?
  • Как проверить, что основная площадка здорова перед переключением?
  • Как минимизировать простой при втором переключении?
  • Что делать, если основная площадка снова упадёт во время failback?

Документируйте и тестируйте процедуры failback вместе с failover.

DR чек-лист

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

  • [ ] RPO и RTO определены и задокументированы
  • [ ] Все критичные данные идентифицированы
  • [ ] Настроены автоматизированные расписания резервного копирования
  • [ ] Резервные копии хранятся вне площадки/между регионами
  • [ ] Включено шифрование резервных копий
  • [ ] Определены политики хранения резервных копий
  • [ ] Для Kubernetes-кластеров запланированы резервные копии etcd

Возможность восстановления

  • [ ] DR-площадка развернута и протестирована
  • [ ] Настроена репликация базы данных
  • [ ] Настроен DNS failover
  • [ ] Runbook восстановления задокументированы
  • [ ] Восстановление тестируется ежеквартально
  • [ ] Процедуры failback задокументированы

Верификация

  • [ ] Автоматизированная проверка резервных копий (еженедельно)
  • [ ] Регулярное тестирование восстановления
  • [ ] Проведены DR-учения
  • [ ] Время восстановления измерено относительно RTO
  • [ ] Целостность данных проверена после восстановления

Связанные статьи Wiki

 
 
 
Языки
Темы
Copyright © 1999 — 2026
Зетка Интерактив