«Backup job succeeded» ≠ «restore capability». Без проверки restore, без измеренного времени восстановления, без подтверждения читаемости данных — backup создаёт ложное чувство безопасности. kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#backing-up-an-etcd-cluster
Цепочка доказательств
Только прохождение всех пяти шагов позволяет утверждать: «Мы можем восстановить кластер».
Scope → Execution → Freshness → Restore Check → Recovery Claim
│ │ │ │ │
│ │ │ │ └─ "Мы можем
│ │ │ │ восстановиться
│ │ │ │ за N минут"
│ │ │ │
│ │ │ └─ Тестовый restore прошёл,
│ │ │ данные читаемы
│ │ │
│ │ └─ backup свежее RPO
│ │
│ └─ backup job завершился успешно
│
└─ Все необходимые компоненты включены в backup
Полный scope backup'а
Каждый элемент обязателен. Отсутствие любого из них делает restore невозможным или неполным.
1. etcd snapshot
Полный снимок состояния кластера — все объекты Kubernetes (Pod'ы, Service'ы, Deployment'ы, Secret'ы, ConfigMap'ы, RBAC, CRD и их instances).
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
Проверка целостности snapshot:
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-20241215-120000.db --write-out=table
2. PKI / сертификаты (/etc/kubernetes/pki/)
CA-сертификат, сертификаты API server, kubelet, front-proxy, etcd peer/client сертификаты. Без них TLS handshake невозможен: компоненты кластера не смогут аутентифицироваться друг у друга, kubelet'ы не подключатся к API server.
tar -czf /backup/pki-$(date +%Y%m%d).tar.gz /etc/kubernetes/pki/
3. Encryption keys (EncryptionConfiguration)
Ключи, которыми зашифрованы Secret'ы в etcd. Путь — файл, указанный в --encryption-provider-config у API server (обычно /etc/kubernetes/enc/encryption-config.yaml).
Без encryption keys после restore etcd Secret'ы будут содержать зашифрованные данные, которые невозможно расшифровать. Все пароли, токены, TLS-сертификаты приложений из Secret'ов — потеряны. Это самая частая причина «успешного restore, который не работает».
4. Static manifests control plane (/etc/kubernetes/manifests/)
Манифесты kube-apiserver, kube-controller-manager, kube-scheduler, etcd как static Pod'ов. Без них kubelet не сможет запустить компоненты control plane.
5. kubeadm config / bootstrap artifacts
ClusterConfiguration, InitConfiguration, join tokens, bootstrap kubeconfig. Обычно хранится в ConfigMap kube-system/kubeadm-config:
kubectl get configmap kubeadm-config -n kube-system -o yaml > /backup/kubeadm-config.yaml
6. CNI и critical addon configs
Конфигурация сетевого плагина (Calico, Cilium, Flannel), CoreDNS, kube-proxy. После restore без CNI Pod'ы не получат сетевое подключение и DNS-резолюция не работает — кластер технически запущен, но неработоспособен.
7. Recovery runbook
Документированная пошаговая процедура восстановления. Без него bus factor = 1. Если единственный человек, знающий процедуру, недоступен во время инцидента — restore невозможен, даже если все backup'ы на месте.
Что НЕ входит в baseline scope
Связь с RPO и RTO
RPO определяет cadence backup'ов
RPO = 15 мин → backup каждые ≤ 15 мин ← корректно
RPO = 15 мин → backup каждый час ← НАРУШЕНИЕ BY DESIGN
Если RPO = 15 минут, а backup снимается раз в час — при аварии в 59-ю минуту после backup'а потеря данных = 59 минут. RPO нарушен в 4 раза, ещё до любой реальной аварии.
RTO определяет требования к скорости restore
RTO = 30 мин → измеренный restore < 30 мин ← корректно
RTO = 30 мин → restore никогда не тестировался ← бесполезно
Влияние на error budget
При SLO 99.95% месячный error budget = ~22 минуты. Один неудачный restore длительностью 45 минут исчерпывает бюджет двух месяцев целиком. Это превращает тестирование restore из «лучшей практики» в экономически обоснованное требование.
Recovery Evidence Maturity Model
Level 0 │ Нет backup'а
Level 1 │ Backup существует (job выполняется)
Level 2 │ Scope проверен (etcd + PKI + keys + manifests + CNI + runbook)
Level 3 │ Freshness мониторится (алерт при > RPO)
Level 4 │ Restore проверяется периодически ← Baseline target
Level 5 │ RTO доказан, Secret'ы читаемы ← Production target
Baseline target: Level 4. Периодическая (не реже раза в неделю) проверка restore в тестовом окружении.
Production target: Level 5. Измеренное время restore укладывается в RTO, данные (включая Secret'ы) читаемы.
Процедура restore из etcd snapshot
# 1. Подготовить чистую control plane ноду с kubeadm, kubelet, container runtime
# 2. Восстановить PKI
cp -r /backup/pki/ /etc/kubernetes/pki/
chmod -R 600 /etc/kubernetes/pki/
# 3. Восстановить encryption keys
cp /backup/encryption-config.yaml /etc/kubernetes/enc/encryption-config.yaml
# 4. Восстановить static manifests
cp /backup/manifests/*.yaml /etc/kubernetes/manifests/
# 5. Восстановить etcd из snapshot
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-20241215-120000.db \
--data-dir=/var/lib/etcd \
--name=master-1 \
--initial-cluster=master-1=https://192.168.1.10:2380 \
--initial-advertise-peer-urls=https://192.168.1.10:2380
# Установить правильного владельца
chown -R etcd:etcd /var/lib/etcd
# 6. Запустить kubelet — static Pod'ы поднимут control plane
systemctl start kubelet
# 7. Проверить состояние
kubectl get nodes
kubectl get pods -A
kubectl get secrets -A # Критично: проверить читаемость Secret'ов
# 8. Восстановить CNI
kubectl apply -f /backup/cni-config.yaml
# 9. Подключить worker-ноды (если нужны новые bootstrap tokens)
kubeadm token create --print-join-command
Проверка читаемости Secret'ов — обязательный шаг. Если encryption keys не были включены в backup или восстановлены некорректно, kubectl get secret <name> -o jsonpath='{.data}' вернёт нечитаемые данные.
Velero: backup данных приложений
Velero бэкапит PersistentVolume данные (через CSI snapshots) и Kubernetes-объекты. velero.io/docs/latest/
# Установка Velero (пример для AWS S3; см. актуальную версию плагина на github.com/vmware-tanzu/velero-plugin-for-aws)
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.14.0 \
--bucket my-velero-bucket \
--backup-location-config region=us-east-1 \
--snapshot-location-config region=us-east-1 \
--use-node-agent
# Создать backup namespace с PV snapshots
velero backup create prod-backup \
--include-namespaces production \
--snapshot-volumes \
--wait
# Проверить состояние backup
velero backup describe prod-backup
# Restore namespace
velero restore create --from-backup prod-backup \
--include-namespaces production \
--wait
# Проверить restore
velero restore describe <restore-name>
Velero и etcd snapshot — дополняющие, а не взаимозаменяемые инструменты. Velero не заменяет etcd snapshot для state control plane; etcd snapshot не покрывает данные в PersistentVolume.
Observability-сигналы для backup/restore
Пример CronJob для periodic restore check и обновления метрик:
apiVersion: batch/v1
kind: CronJob
metadata:
name: restore-check
namespace: kube-system
spec:
schedule: "0 2 * * *" # Каждую ночь в 02:00
jobTemplate:
spec:
template:
spec:
containers:
- name: restore-checker
image: bitnami/etcd:3.5
command:
- /bin/sh
- -c
- |
START=$(date +%s)
etcdctl snapshot restore /backup/latest.db \
--data-dir=/tmp/etcd-test
END=$(date +%s)
DURATION=$((END - START))
# Push metrics to Pushgateway
echo "restore_check_duration_seconds $DURATION" | \
curl --data-binary @- http://pushgateway:9091/metrics/job/restore-check
echo "restore_check_last_success $(date +%s)" | \
curl --data-binary @- http://pushgateway:9091/metrics/job/restore-check
restartPolicy: OnFailure
Когда использовать
- Production кластер с любыми stateful workloads — etcd snapshot обязателен. Без него кластер не восстановим.
- RPO < 1 час — автоматизированный backup через CronJob или Velero schedule. Ручной backup не масштабируется.
- Multi-master кластер — snapshot нужно снимать с одного члена etcd кластера; остальные члены не нужно snapshot'ировать отдельно (snapshot содержит полное состояние).
- Managed Kubernetes (EKS, GKE, AKS) — провайдер управляет etcd backup'ом control plane. Но PersistentVolume данные приложений — всё равно ответственность команды. Velero или CSI snapshots обязательны.
- Dev/staging кластеры — backup опционален, если кластер воспроизводим через IaC за < 30 минут.
Типичные ошибки
1. Encryption keys не включены в backup Самая частая причина «успешного restore, который не работает». После restore из etcd snapshot все Secret'ы содержат зашифрованные данные, которые невозможно расшифровать без ключей. Все application credentials потеряны. Решение: encryption keys — часть backup scope, хранить в отдельном безопасном месте (HSM, Vault).
2. Snapshot снимается с работающего etcd без --cacert/--cert/--key
Команда etcdctl snapshot save без TLS-сертификатов работает только если etcd настроен без TLS (что само по себе проблема безопасности). В kubeadm-кластерах etcd всегда использует mTLS.
3. Restore никогда не тестировался Level 1 в maturity model. При реальной аварии обнаруживается corruption snapshot, несовместимость версий etcd, или отсутствие encryption keys. Правило: тестовый restore — еженедельно в изолированном окружении.
4. Velero backup без --snapshot-volumes
Velero по умолчанию не делает снимки PersistentVolume. Backup содержит только Kubernetes-объекты (манифесты), но не данные баз данных. После restore PVC пустые.
5. Один backup destination без offsite копии Backup хранится на той же ноде, что и etcd. При отказе ноды теряются и данные, и backup. Правило: backup хранится минимум в двух местах, одно из которых offsite (S3, GCS, другой datacenter).
6. kubeadm-config ConfigMap не включён в backup
После restore кластера без kubeadm-config невозможно корректно добавить ноды или провести upgrade. Решение: kubectl get cm kubeadm-config -n kube-system -o yaml — часть backup процедуры.
Альтернативы
Velero Backup и restore Kubernetes-объектов и PersistentVolume данных. Интегрируется с CSI snapshot API (k8s 1.20+). Поддерживает schedule, retention, namespace mapping при restore. Стандарт для application-level backup. Не заменяет etcd snapshot для control plane state. velero.io
etcdctl + CronJob Нативный подход без зависимостей. Минус: только etcd state, без PV данных. Плюс: минимум зависимостей, максимум контроля. Подходит для control plane backup.
CSI Volume Snapshots Стандартный Kubernetes API для снимков PersistentVolume. Работает на уровне storage driver. kubernetes.io/docs/concepts/storage/volume-snapshots/ Требует CSI driver с поддержкой снимков (большинство cloud CSI drivers поддерживают).
Kasten K10 (Veeam) Enterprise-grade backup для Kubernetes. Policy-based, с поддержкой compliance, encryption, multi-cloud. Дороже Velero, но значительно богаче по функциональности для enterprise требований.
Cluster Backup через GitOps (Flux/ArgoCD) Если весь state кластера задекларирован в Git (GitOps-подход), то «restore» — это пересоздание кластера и apply Git state. Не покрывает PV данные, но для stateless workloads может быть достаточно. etcd snapshot всё равно нужен для CRD instances и объектов, не управляемых через GitOps.