Restic ile Docker Volume Yedekleme: Adım Adım Rehber

Docker ortamında veri kaybı yaşamak, özellikle production’da çalışan container’lar söz konusuysa gerçekten kabusu andıran bir deneyim. Volume’lar silinir, container yanlışlıkla kaldırılır ya da host sunucu tamamen çöker. İşte tam bu noktada Restic devreye giriyor. Hafif, hızlı, şifrelenmiş ve incremental yedekleme sunan Restic, Docker volume yedekleme için mükemmel bir araç. Bu yazıda sıfırdan kurulumdan otomatik yedekleme sistemine kadar her şeyi ele alacağız.

Restic Nedir ve Neden Docker Volume İçin İdeal?

Restic, Go ile yazılmış modern bir yedekleme aracı. Klasik yedekleme araçlarından farkı şu: her yedek kendi içinde tam bir snapshot ama aslında sadece değişen bloklar yazılıyor (deduplication). Yani 10 GB’lık bir volume’ü her gün yedeklesen bile disk kullanımı katlanarak artmıyor.

Docker volume yedekleme için birkaç önemli özelliği öne çıkıyor:

  • Şifreleme: Yedekler AES-256 ile şifrelenmiş gidiyor. Uzak sunucuya göndersen bile veri güvenli.
  • Deduplication: Aynı bloklar tekrar yazılmıyor, disk alanı verimli kullanılıyor.
  • Çoklu backend desteği: SFTP, S3, B2, Azure, Google Cloud ve daha fazlası.
  • Hızlı restore: Belirli bir snapshot’tan sadece ihtiyaç duyulan dosyaları geri yükleyebiliyorsun.
  • Hafif kaynak kullanımı: Production ortamında çalışırken sistemi yormayan bir yapı.

Docker volume’leri /var/lib/docker/volumes/ altında tutuluyor. Ama doğrudan bu dizini yedeklemek her zaman en temiz yöntem değil. Özellikle çalışan bir veritabanı container’ı varsa, dosyalar tutarsız durumda yakalanabilir. Bunu nasıl çözeceğimizi de göreceğiz.

Restic Kurulumu

Linux (Debian/Ubuntu)

# Paket deposundan kurulum
sudo apt update
sudo apt install restic -y

# Ya da en güncel sürümü direkt indirmek için
restic self-update

# Versiyon kontrolü
restic version

Linux (RHEL/CentOS/Rocky)

sudo dnf install restic -y
# ya da
sudo yum install epel-release -y
sudo yum install restic -y

Binary olarak indirme (her dağıtım için geçerli)

# GitHub'dan en son release'i indir
wget https://github.com/restic/restic/releases/download/v0.16.4/restic_0.16.4_linux_amd64.bz2
bunzip2 restic_0.16.4_linux_amd64.bz2
chmod +x restic_0.16.4_linux_amd64
sudo mv restic_0.16.4_linux_amd64 /usr/local/bin/restic

Repository Oluşturma ve İlk Yapılandırma

Restic’te yedekler bir “repository” içinde tutuluyor. Repository, şifrelenmiş yedeklerin saklandığı dizin ya da uzak depolama alanı. İlk kullanımdan önce bu repository’yi başlatmak gerekiyor.

SFTP Repository (Uzak Sunucu)

# SSH key tabanlı bağlantı için önce key kopyala
ssh-copy-id [email protected]

# SFTP repository başlat
restic -r sftp:[email protected]:/backup/docker-volumes init

# Parola soracak, güçlü bir parola belirle ve kaydet
# Enter password for new repository: ****
# Enter password again: ****
# created restic repository abc123def at sftp:[email protected]:/backup/docker-volumes

S3 Uyumlu Depolama (MinIO veya AWS S3)

# Environment variable olarak kimlik bilgilerini tanımla
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"

# AWS S3 için
restic -r s3:s3.amazonaws.com/bucket-adi init

# MinIO için (self-hosted)
restic -r s3:http://minio.sirket.local:9000/docker-backups init

Local Repository (Test için)

# Test amaçlı local repository
restic -r /mnt/backup-disk/docker-volumes init

Ortam Değişkenlerini Yönetme

Her komutta parola ve repository bilgisini yazmamak için environment variable kullanmak en temiz yöntem. Bunu bir dosyaya yazıp source edebilirsin.

# /etc/restic/env dosyası oluştur
sudo mkdir -p /etc/restic
sudo tee /etc/restic/env << 'EOF'
export RESTIC_REPOSITORY="sftp:[email protected]:/backup/docker-volumes"
export RESTIC_PASSWORD="super-guclu-parola-buraya"
# S3 kullanıyorsan bunları da ekle
# export AWS_ACCESS_KEY_ID="key"
# export AWS_SECRET_ACCESS_KEY="secret"
EOF

sudo chmod 600 /etc/restic/env

# Kullanım
source /etc/restic/env
restic snapshots

Docker Volume Yedekleme Stratejileri

Yöntem 1: Çalışan Container’dan Volume Yedekleme

Bu yöntemde container’ı durdurmadan yedekleme yapılıyor. Stateless uygulamalar için uygun ama veritabanları için riskli.

# Volume listesini gör
docker volume ls

# Belirli bir volume'ü yedekle
source /etc/restic/env
restic backup /var/lib/docker/volumes/uygulam_data/_data 
  --tag docker-volume 
  --tag uygulama_data 
  --hostname $(hostname)

Yöntem 2: Container’ı Durdurarak Güvenli Yedekleme

Veritabanı gibi kritik servisler için en güvenli yöntem.

#!/bin/bash
# /usr/local/bin/backup-docker-volume.sh

source /etc/restic/env

CONTAINER_NAME="postgres_db"
VOLUME_NAME="postgres_data"
VOLUME_PATH="/var/lib/docker/volumes/${VOLUME_NAME}/_data"

echo "$(date): Yedekleme başlatılıyor..."

# Container'ı durdur
docker stop $CONTAINER_NAME
echo "Container durduruldu: $CONTAINER_NAME"

# Yedekle
restic backup $VOLUME_PATH 
  --tag "docker-volume" 
  --tag "$VOLUME_NAME" 
  --tag "$(date +%Y-%m-%d)"

BACKUP_STATUS=$?

# Container'ı yeniden başlat
docker start $CONTAINER_NAME
echo "Container yeniden başlatıldı: $CONTAINER_NAME"

if [ $BACKUP_STATUS -eq 0 ]; then
  echo "$(date): Yedekleme başarıyla tamamlandı."
else
  echo "$(date): HATA - Yedekleme başarısız!" >&2
  exit 1
fi

Yöntem 3: Docker Exec ile Veritabanı Dump Alarak Yedekleme

Bu benim en çok tercih ettiğim yöntem. Container’ı durdurmak yerine veritabanının kendi dump mekanizmasını kullanıyoruz.

#!/bin/bash
# /usr/local/bin/backup-postgres-restic.sh

source /etc/restic/env

CONTAINER_NAME="postgres_db"
DB_NAME="production_db"
DB_USER="postgres"
BACKUP_DIR="/tmp/db-dumps"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

echo "$(date): PostgreSQL dump alınıyor..."

# PostgreSQL dump
docker exec $CONTAINER_NAME 
  pg_dump -U $DB_USER $DB_NAME 
  > "${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql"

if [ $? -ne 0 ]; then
  echo "HATA: pg_dump başarısız!" >&2
  exit 1
fi

echo "Dump tamamlandı. Restic ile yedekleniyor..."

# Restic ile yedekle
restic backup "${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql" 
  --tag "postgres-dump" 
  --tag "$DB_NAME" 
  --tag "$TIMESTAMP"

# Geçici dosyayı temizle
rm -f "${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.sql"

echo "$(date): Tamamlandı."

Yöntem 4: Docker ile Restic’i Container Olarak Çalıştırma

Bazı ortamlarda Restic’i host’a kurmak istemeyebilirsin. Bu durumda Restic’i container olarak çalıştırabilirsin.

# Restic container ile volume yedekleme
docker run --rm 
  -v /var/lib/docker/volumes/uygulama_data/_data:/data:ro 
  -v /root/.ssh:/root/.ssh:ro 
  -e RESTIC_REPOSITORY="sftp:[email protected]:/backup/docker-volumes" 
  -e RESTIC_PASSWORD="parola" 
  restic/restic backup /data 
  --tag docker-volume 
  --tag uygulama_data

Snapshot Yönetimi

Restic’in güzel yanlarından biri snapshot yönetimi. Her yedek bir snapshot olarak kaydediliyor ve bunları kolayca listeleyip yönetebiliyorsun.

source /etc/restic/env

# Tüm snapshot'ları listele
restic snapshots

# Belirli bir tag'e göre filtrele
restic snapshots --tag postgres-dump

# Snapshot içeriğini listele
restic ls latest

# Belirli bir snapshot'ın içeriğini gör
restic ls abc123de

# Snapshot istatistiklerini gör
restic stats

Eski Yedekleri Otomatik Temizleme (Retention Policy)

Sonsuz yedek tutmak disk alanını tüketir. Restic’in forget ve prune komutları ile retention policy tanımlayabilirsin.

source /etc/restic/env

# Retention policy uygula
restic forget 
  --keep-last 5 
  --keep-daily 7 
  --keep-weekly 4 
  --keep-monthly 6 
  --tag docker-volume 
  --prune

# Parametreler:
# --keep-last 5: Son 5 yedek her durumda korunur
# --keep-daily 7: Her günün son yedeği, 7 gün boyunca
# --keep-weekly 4: Her haftanın son yedeği, 4 hafta boyunca
# --keep-monthly 6: Her ayın son yedeği, 6 ay boyunca
# --prune: Kullanılmayan veri bloklarını hemen temizle

Yedekten Geri Yükleme

Felaket anında panik yapmadan geri yükleme yapabilmek için bu adımları önceden bilmek gerekiyor.

source /etc/restic/env

# Snapshot listesini gör
restic snapshots

# En son snapshot'tan tüm veriyi geri yükle
restic restore latest --target /tmp/restore-test

# Belirli bir snapshot'tan geri yükle
restic restore abc123de --target /var/lib/docker/volumes/uygulama_data/_data

# Sadece belirli bir dosyayı geri yükle
restic restore latest 
  --target /tmp/restore 
  --include "/production_db_20240115_120000.sql"

# PostgreSQL dump'ı geri yükle
restic restore latest 
  --target /tmp/restore 
  --tag postgres-dump

# Dump'ı PostgreSQL'e yükle
docker exec -i postgres_db 
  psql -U postgres production_db 
  < /tmp/restore/production_db_20240115_120000.sql

Tam Otomatik Yedekleme Scripti

Tüm bunları bir araya getiren, production’da kullanabileceğin kapsamlı bir script:

#!/bin/bash
# /usr/local/bin/docker-full-backup.sh
# Tüm Docker volume'lerini yedekler, log tutar, hata bildirir

set -euo pipefail

# Konfigürasyon
source /etc/restic/env
LOG_FILE="/var/log/restic-docker-backup.log"
ALERT_EMAIL="[email protected]"
BACKUP_TAG="docker-volumes-$(date +%Y%m%d)"

log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

send_alert() {
  echo "$1" | mail -s "RESTIC BACKUP HATA: $(hostname)" $ALERT_EMAIL 2>/dev/null || true
}

log "=== Yedekleme başlatıldı ==="

# Tüm volume'leri yedekle
VOLUMES=$(docker volume ls -q)
BACKUP_ERRORS=0

for VOLUME in $VOLUMES; do
  VOLUME_PATH="/var/lib/docker/volumes/${VOLUME}/_data"

  if [ ! -d "$VOLUME_PATH" ]; then
    log "UYARI: $VOLUME için dizin bulunamadı, atlanıyor."
    continue
  fi

  log "Volume yedekleniyor: $VOLUME"

  restic backup "$VOLUME_PATH" 
    --tag "docker-volume" 
    --tag "$VOLUME" 
    --tag "$BACKUP_TAG" 
    --exclude "*.tmp" 
    --exclude "*.log" 
    >> $LOG_FILE 2>&1 || {
    log "HATA: $VOLUME yedeklenemedi!"
    BACKUP_ERRORS=$((BACKUP_ERRORS + 1))
  }
done

# Retention policy uygula
log "Eski yedekler temizleniyor..."
restic forget 
  --keep-last 5 
  --keep-daily 7 
  --keep-weekly 4 
  --keep-monthly 3 
  --tag docker-volume 
  --prune >> $LOG_FILE 2>&1

# Repository bütünlüğünü kontrol et
log "Repository kontrolü yapılıyor..."
restic check >> $LOG_FILE 2>&1

if [ $BACKUP_ERRORS -gt 0 ]; then
  MSG="$BACKUP_ERRORS volume yedeklenemedi! Log: $LOG_FILE"
  log "KRITIK HATA: $MSG"
  send_alert "$MSG"
  exit 1
fi

log "=== Yedekleme başarıyla tamamlandı ==="

Cron ile Otomatik Zamanlama

# Crontab düzenle
sudo crontab -e

# Her gece 02:00'de yedekle
0 2 * * * /usr/local/bin/docker-full-backup.sh >> /var/log/restic-cron.log 2>&1

# PostgreSQL dump yedeklemesi her 6 saatte bir
0 */6 * * * /usr/local/bin/backup-postgres-restic.sh >> /var/log/restic-postgres.log 2>&1

Systemd timer kullanmak isteyenler için daha güvenilir bir alternatif:

# /etc/systemd/system/restic-backup.service
sudo tee /etc/systemd/system/restic-backup.service << 'EOF'
[Unit]
Description=Restic Docker Volume Backup
After=network.target docker.service

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/local/bin/docker-full-backup.sh
StandardOutput=journal
StandardError=journal
EOF

# /etc/systemd/system/restic-backup.timer
sudo tee /etc/systemd/system/restic-backup.timer << 'EOF'
[Unit]
Description=Restic Backup Timer
Requires=restic-backup.service

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable restic-backup.timer
sudo systemctl start restic-backup.timer

# Timer durumunu kontrol et
sudo systemctl list-timers restic-backup.timer

Yedekleme Doğrulama ve Test

Yedek aldın ama test etmediysen yoktur. Bu basit gerçeği asla unutma.

source /etc/restic/env

# Repository bütünlüğünü kontrol et
restic check

# Derin kontrol (tüm veriyi doğrula, zaman alır)
restic check --read-data

# Test restore yap
mkdir -p /tmp/restore-test
restic restore latest --target /tmp/restore-test --tag postgres-dump

# Geri yüklenen dosyaları kontrol et
ls -lah /tmp/restore-test/

# Temizle
rm -rf /tmp/restore-test

Güvenlik Önerileri

Restic ile yedekleme yaparken güvenliği de göz önünde bulundurmak gerekiyor:

  • Repository parolası: Uzun, rastgele ve bir parola yöneticisinde saklanan bir parola kullan. Bu parolayı kaybedersen yedeklere bir daha erişemezsin.
  • SSH key izinleri: Yedekleme için kullanılan SSH key’inin chmod 600 ile korunduğundan emin ol.
  • /etc/restic/env dosyası: chmod 600 ve chown root:root ile sadece root erişimine kısıtla.
  • Append-only repository: Uzak sunucuda yanlışlıkla ya da bir saldırı sonucu yedeklerin silinmesini önlemek için SFTP kullanıyorsan uzak sunucuda append-only mod ayarla.
  • Parola yedeklemesi: Repository parolasını fiziksel olarak da (kağıt, kasada saklı) yedekle. Ciddi söylüyorum.
  • Offsite yedekleme: İdeal olarak yedeklerin en az birini farklı bir fiziksel lokasyonda tut.

Gerçek Dünya Senaryosu: WordPress + MySQL Stack

Diyelim ki bir Docker Compose ile çalışan WordPress siteniz var. Bu stack için tam yedekleme akışı şöyle olabilir:

#!/bin/bash
# /usr/local/bin/backup-wordpress-stack.sh

source /etc/restic/env

COMPOSE_DIR="/opt/wordpress"
MYSQL_CONTAINER="wordpress_mysql_1"
MYSQL_ROOT_PASSWORD="db-root-parola"
MYSQL_DB="wordpress"
DUMP_PATH="/tmp/wordpress_mysql_dump.sql"
WP_VOLUME="/var/lib/docker/volumes/wordpress_wp_data/_data"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"; }

log "WordPress yedekleme başlıyor..."

# MySQL dump al
log "MySQL dump alınıyor..."
docker exec $MYSQL_CONTAINER 
  mysqldump -u root -p"${MYSQL_ROOT_PASSWORD}" $MYSQL_DB 
  > $DUMP_PATH

# WordPress dosyaları + MySQL dump birlikte yedekle
log "Restic ile yedekleniyor..."
restic backup 
  $WP_VOLUME 
  $DUMP_PATH 
  --tag "wordpress" 
  --tag "$(date +%Y-%m-%d)"

# Retention
restic forget 
  --keep-daily 7 
  --keep-weekly 4 
  --tag wordpress 
  --prune

rm -f $DUMP_PATH
log "WordPress yedekleme tamamlandı."

Sonuç

Restic ile Docker volume yedekleme, doğru kurulduğunda bakım gerektirmeyen, güvenilir bir sistem haline geliyor. Önemli olan birkaç nokta var:

Birincisi, yedekleme stratejini verinin türüne göre belirle. Veritabanları için dump al, stateless volume’ler için doğrudan yedekleyebilirsin. İkincisi, retention policy’yi en baştan kur. Disk dolmadan önce eski yedeklerin temizlenmesi gerekiyor. Üçüncüsü ve en önemlisi, yedeklerini düzenli olarak test et. Ayda bir test restore yapma alışkanlığı edinin. Felaket anında test etmemiş bir yedek seni kurtarmaz.

Repository parolasını güvenli bir yerde saklayın, yedeklerin uzak lokasyonda tutulduğundan emin olun ve sistemin çalıştığını log’lardan takip edin. Bu üç prensibi uyguladıktan sonra Docker ortamında veri kaybı korkusuyla uyumak zorunda kalmayacaksınız.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir