Disaster Recovery #
Backup yang tidak pernah di-test sama saja tidak ada. Disaster recovery plan yang hanya ada di dokumen tapi tidak pernah dipraktikkan akan gagal saat paling dibutuhkan. Artikel ini membahas komponen-komponen disaster recovery untuk Kubernetes cluster — dari backup yang benar sampai strategi failover — dengan fokus pada hal-hal yang bisa dieksekusi ketika insiden nyata terjadi di jam 3 pagi.
Apa yang Perlu Di-backup #
Kubernetes cluster punya dua jenis "state" yang perlu di-backup:
1. Cluster state (etcd):
→ Definisi semua resource Kubernetes (Deployment, Service, ConfigMap, dll)
→ Tanpa ini: cluster kosong, harus deploy ulang semua dari scratch
→ Solusi ideal: simpan manifest di Git (GitOps) — tidak perlu backup etcd
2. Data persistent (PersistentVolumes):
→ Database, file uploads, state aplikasi
→ Ini tidak ada di Git, ini adalah data user
→ WAJIB di-backup, ini yang paling kritikal
Velero: Backup Namespace Kubernetes #
Velero adalah tool yang bisa backup dan restore seluruh namespace Kubernetes, termasuk resource definitions dan PersistentVolumes:
# Install Velero (contoh: backup ke AWS S3)
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket my-velero-backups \
--backup-location-config region=ap-southeast-1 \
--snapshot-location-config region=ap-southeast-1 \
--secret-file ./credentials-velero
# Backup satu namespace
velero backup create production-backup-20240115 \
--include-namespaces production
# Backup seluruh cluster
velero backup create full-cluster-backup \
--include-namespaces "*"
# Lihat status backup
velero backup describe production-backup-20240115
velero backup logs production-backup-20240115
# Schedule backup otomatis setiap hari jam 2 pagi
velero schedule create daily-production-backup \
--schedule="0 2 * * *" \
--include-namespaces production \
--ttl 720h # simpan 30 hari
Restore dengan Velero #
# Restore namespace dari backup
velero restore create \
--from-backup production-backup-20240115 \
--include-namespaces production
# Restore ke namespace berbeda (untuk testing restore)
velero restore create \
--from-backup production-backup-20240115 \
--namespace-mappings production:production-restore-test
# Lihat status restore
velero restore describe <restore-name>
velero restore logs <restore-name>
# Restore resource tertentu saja
velero restore create \
--from-backup production-backup-20240115 \
--include-resources deployments,services,configmaps
# ⚠ PENTING: test restore secara regular!
# Jadwalkan restore test ke namespace staging setiap bulan
Backup Database Terpisah dari Velero #
Untuk database, snapshot disk (yang dilakukan Velero) seringkali tidak cukup — snapshot bisa dalam state yang inconsistent jika diambil saat database sedang write. Gunakan database-native backup:
# CronJob untuk backup PostgreSQL ke S3
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
namespace: production
spec:
schedule: "0 1 * * *" # setiap hari jam 1 pagi
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: postgres:16
command:
- /bin/sh
- -c
- |
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="backup_${TIMESTAMP}.sql.gz"
# Dump database
PGPASSWORD=$DB_PASSWORD pg_dump \
-h $DB_HOST -U $DB_USER -d $DB_NAME \
| gzip > /tmp/${BACKUP_FILE}
# Upload ke S3
aws s3 cp /tmp/${BACKUP_FILE} \
s3://my-db-backups/postgres/${BACKUP_FILE}
echo "Backup selesai: ${BACKUP_FILE}"
# Hapus backup lokal lebih dari 7 hari di S3
aws s3 ls s3://my-db-backups/postgres/ \
| awk '{print $4}' \
| sort -r | tail -n +8 \
| xargs -I {} aws s3 rm s3://my-db-backups/postgres/{}
env:
- name: DB_HOST
value: "postgres-service"
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
- name: DB_NAME
value: "production_db"
Strategi Multi-Cluster untuk DR #
Untuk aplikasi kritikal dengan RTO rendah, satu cluster tidak cukup:
Strategi 1: Active-Passive (Failover)
Region A: cluster aktif, menerima semua traffic
Region B: cluster standby, ter-deploy tapi tidak menerima traffic
Failover:
→ Deteksi region A down
→ Update DNS untuk arahkan traffic ke region B
→ RTO: 5-15 menit (waktu DNS propagation + health check)
→ RPO: tergantung frekuensi replikasi data ke region B
Strategi 2: Active-Active
Region A: menerima 50% traffic
Region B: menerima 50% traffic
Keuntungan:
→ RTO ~0 (jika satu region down, traffic otomatis ke yang lain)
→ No wasted capacity (berbeda dari active-passive)
Tantangan:
→ Data consistency antar region (database multi-master)
→ Jauh lebih kompleks untuk stateful workload
→ Biaya 2x karena kedua region penuh
Strategi 3: GitOps Cluster Recreation
→ Tidak ada cluster standby
→ Semua manifest di Git
→ Saat disaster: buat cluster baru, apply manifest dari Git
→ RTO: 30-60 menit (provisioning + deploy semua aplikasi)
→ Cocok untuk aplikasi yang bisa toleransi RTO >30 menit
Mendefinisikan RTO dan RPO #
RTO (Recovery Time Objective):
Berapa lama maksimum sistem boleh tidak available?
Contoh: "Maksimum 15 menit downtime per insiden"
RPO (Recovery Point Objective):
Berapa banyak data maksimum yang boleh hilang?
Contoh: "Maksimum kehilangan data 1 jam terakhir"
Mapping ke strategi:
RTO < 1 menit:
→ Active-Active multi-region
→ Tidak ada single point of failure sama sekali
RTO 5-15 menit:
→ Active-Passive dengan automated failover
→ DNS TTL rendah, health check cepat
RTO 30-60 menit:
→ GitOps recreation
→ Backup restore dari Velero + S3
RPO < 1 jam:
→ Database replikasi sync ke region lain
→ Backup setiap jam
RPO < 24 jam:
→ Daily backup sudah cukup
→ Velero schedule harian
Runbook Recovery: Template #
Runbook: Cluster Gagal Total
Severity: Critical
Waktu respons: Segera
LANGKAH 1: Konfirmasi cluster down (5 menit)
□ kubectl get nodes → timeout atau error
□ Cek cloud provider console: apakah control plane healthy?
□ Cek status page cloud provider
□ Notify tim dan stakeholder via Slack/PagerDuty
LANGKAH 2: Putuskan strategi (2 menit)
□ Apakah ada cluster DR/standby? → Lanjut ke Langkah 3A
□ Tidak ada cluster DR? → Lanjut ke Langkah 3B
LANGKAH 3A: Failover ke cluster standby
□ Update DNS/Load Balancer ke cluster standby
□ Verifikasi traffic sudah pindah
□ Verifikasi semua health check passing
□ Monitor untuk 30 menit
LANGKAH 3B: Recreate cluster dari Git
□ Provision cluster baru via Terraform/gcloud/eksctl
□ kubectl apply -k overlays/production
□ Restore database dari backup terbaru
□ Verifikasi semua service running
□ Smoke test endpoint production
□ Update DNS/Load Balancer
LANGKAH 4: Post-recovery
□ Root cause analysis
□ Update runbook jika perlu
□ Post-mortem dalam 48 jam
Ringkasan #
- GitOps adalah backup cluster state terbaik — jika semua manifest ada di Git, recreate cluster hanya perlu
kubectl apply -k; tidak perlu backup etcd yang kompleks.- Velero untuk backup PersistentVolume dan resource definitions — terutama untuk namespace yang punya data persistent; schedule daily backup dan test restore setiap bulan.
- Database backup terpisah dari snapshot disk — snapshot disk bisa inconsistent saat database sedang write; gunakan
pg_dumpatau backup tool database-native.- Test restore secara regular — backup yang tidak pernah di-test tidak bisa dipercaya; restore ke namespace test setiap bulan sebagai bagian DR drill.
- Definisikan RTO dan RPO sebelum insiden — tanpa target yang jelas, tidak ada strategi yang tepat; RTO <15 menit butuh active-passive; RTO <1 menit butuh active-active.
- Runbook yang bisa diikuti oleh engineer baru — dokumentasi recovery yang mengasumsikan pengetahuan mendalam tidak berguna saat insiden pukul 3 pagi; buat step-by-step yang eksplisit.