🎯 DR Strategies — The Four Tiers
Choose your DR strategy based on your RTO/RPO requirements and budget. Each tier roughly doubles cost while halving recovery time.
Backup & Restore
RTO: hours
RPO: hours
Cost: lowest
etcd snapshots + Velero to S3. Restore to a new cluster when primary fails.
Pilot Light
RTO: 30–60 min
RPO: minutes
Cost: low
Minimal cluster running in DR region. Scale up and restore data on failover.
Warm Standby
RTO: 5–30 min
RPO: seconds
Cost: medium
Full cluster at reduced capacity. Database replicated. Scale up on failover.
Active-Active
RTO: seconds
RPO: near-zero
Cost: highest
Two full clusters, both serving traffic. DNS failover or global LB.
RTO & RPO Definitions
| Term | Definition | Typical targets by tier |
|---|---|---|
| RTO (Recovery Time Objective) | Maximum acceptable time from disaster to full service recovery | Tier 1: 4h | Tier 2: 1h | Tier 3: 15m | Tier 4: <1m |
| RPO (Recovery Point Objective) | Maximum acceptable data loss measured in time | Tier 1: 1h | Tier 2: 15m | Tier 3: 1m | Tier 4: <1s |
| MTTR (Mean Time to Recovery) | Average time to restore service after an incident | Measure from incidents; improve iteratively |
| MTBF (Mean Time Between Failures) | Average time between incidents | Track to understand failure frequency |
💾 What to Back Up & How Often
| Data | Tool | Frequency | Retention | Storage |
|---|---|---|---|---|
| etcd cluster state | etcdctl snapshot | Hourly | 7 days | S3 cross-region |
| Persistent Volume data | Velero + CSI snapshots | Hourly | 7 days | S3 / cloud snapshots |
| Application manifests | Git (ArgoCD/Flux) | Continuous (every commit) | Permanent | Git remote |
| Secrets | External Secrets store | Real-time (ESO) | Vault/AWS SM versioning | Secrets manager |
| Container images | Harbor replication | On push | Permanent (semver tags) | Cross-region registry |
| Helm values / Kustomize overlays | Git | Continuous | Permanent | Git remote |
| Observability data | Prometheus remote_write to Mimir | Continuous | 13 months | S3 |
Automated etcd Backup CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup
namespace: kube-system
spec:
schedule: "0 * * * *" # every hour
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
hostNetwork: true
nodeName: cp-1 # run on first control-plane node
containers:
- name: etcd-backup
image: bitnami/etcd:3.5
command:
- /bin/sh
- -c
- |
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/apiserver-etcd-client.crt \
--key=/etc/kubernetes/pki/apiserver-etcd-client.key
aws s3 cp /backup/etcd-$(date +%Y%m%d-%H%M).db \
s3://my-etcd-backups/$(date +%Y/%m/%d)/ \
--storage-class STANDARD_IA
volumeMounts:
- name: etcd-certs
mountPath: /etc/kubernetes/pki/etcd
readOnly: true
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
restartPolicy: OnFailure
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
Velero Scheduled Backup for PV Data
velero schedule create hourly-production \
--schedule="@every 1h" \
--include-namespaces production,staging \
--ttl 168h \
--storage-location default
# Monitor backup health
velero backup get
velero schedule get
# Alert if latest backup is older than 2 hours (Prometheus)
# time() - velero_backup_last_successful_timestamp > 7200
🌍 Multi-Region & Cluster Failover
Global Load Balancer
AWS Global Accelerator, GCP Cloud Load Balancing, or Cloudflare directs traffic to the nearest healthy region. Health checks detect region failure in <10s.
Database Replication
Cross-region database replication (RDS Multi-AZ + read replica, CloudSQL HA, CockroachDB) is the hardest part of active-active. Define write locality.
Image Registry Replication
Harbor geo-replication or ECR cross-region replication ensures images are available in the DR region before you need them — not during the incident.
DNS TTL Management
Reduce DNS TTL to 60s 24h before planned failover tests. In active-active, use low TTL always (30–60s) to enable fast failover.
Active-Active Multi-Cluster with Submariner
# Submariner creates an encrypted overlay between clusters
# allowing cross-cluster service discovery and pod-to-pod routing
# Install on both clusters
subctl deploy-broker --kubeconfig primary.kubeconfig
subctl join broker-info.subm \
--kubeconfig secondary.kubeconfig \
--clusterid secondary
# Export a service to be discoverable from other clusters
kubectl apply -f - <<EOF
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
name: my-api
namespace: production
EOF
# From secondary cluster, discover the service
kubectl get serviceimport -n production
# Access via: my-api.production.svc.clusterset.local
Cluster Failover Runbook (Backup & Restore tier)
- Declare incident — alert on-call team, open incident channel, assign incident commander
- Assess primary cluster — determine if recoverable or if full DR activation is needed
- Point DNS to DR region — update Route53/Cloud DNS health-check target or lower TTL to failover
- Provision DR cluster — use Terraform/Pulumi IaC; cluster should provision in 5–10 min
- Restore etcd snapshot —
etcdctl snapshot restorefrom latest S3 backup (see lesson 83) - Bootstrap GitOps — install ArgoCD, apply root Application; manifests auto-apply from Git
- Restore PV data —
velero restore create --from-backup <latest> - Validate services — run smoke tests against DR endpoints, check database connectivity
- Communicate status — update status page, notify stakeholders, estimated recovery time
- Post-incident — write PIR (Post-Incident Review), update runbook with lessons learned
💥 Chaos Engineering & DR Testing
An untested DR plan is not a DR plan. Chaos engineering deliberately injects failures in controlled conditions to validate that your system handles them gracefully — and that your runbooks actually work.
LitmusChaos — Kubernetes-Native Chaos
helm repo add litmuschaos https://litmuschaos.github.io/litmus-helm
helm install chaos litmuschaos/litmus \
--namespace litmus \
--create-namespace
# Pod Delete experiment — kills random pods in a namespace
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
name: pod-delete-chaos
namespace: production
spec:
appinfo:
appns: production
applabel: "app=my-api"
appkind: deployment
chaosServiceAccount: pod-delete-sa
experiments:
- name: pod-delete
spec:
components:
env:
- name: TOTAL_CHAOS_DURATION
value: "60" # run for 60 seconds
- name: CHAOS_INTERVAL
value: "10" # delete a pod every 10s
- name: FORCE
value: "false" # graceful termination
probe:
- name: check-availability
type: httpProbe
httpProbe/inputs:
url: https://my-api.example.com/health
insecureSkipVerify: false
responseTimeout: 5000
runProperties:
probeTimeout: 10
interval: 2
attempt: 10
DR Testing Schedule
| Test | Frequency | What to validate |
|---|---|---|
| Single pod kill | Continuous (CI) | Pod restarts, readiness probe, PDB holds |
| Node drain | Weekly | Pods reschedule cleanly, PDBs respected, no data loss |
| etcd snapshot restore | Monthly | Full restore to a fresh cluster within RTO |
| Velero restore drill | Monthly | PV data recoverable within RPO |
| Zone failure simulation | Quarterly | Services survive AZ loss, traffic reroutes |
| Full region failover | Annually | End-to-end DR runbook executes within RTO, data loss within RPO |
Key DR Metrics to Track
Actual vs Target RTO
Measure time from incident declaration to full service restoration in every DR test. Is it within your SLA target?
Backup Success Rate
Alert when velero_backup_success_total or etcd snapshot jobs fail. A backup you don't know failed is not a backup.
Restore Test Results
Track every restore drill — success/failure, actual RTO, data loss observed. Trend over time to show DR capability improvement.
MTTR Trend
Calculate mean time to recovery from all incidents. A decreasing MTTR means your runbooks and automation are improving.