Jenkins Backup ve Restore Stratejileri: Verilerinizi Koruyun
Jenkins kurulumunuzu emekle yapılandırdınız, pipeline’larınızı yazdınız, job’larınızı düzenlediniz ve her şey mükemmel çalışıyor. Sonra bir gün sunucu diskinde kritik bir bozulma yaşanıyor ya da yanlışlıkla yapılan bir güncelleme her şeyi mahvediyor. İşte tam bu noktada “acaba backup almış mıydım?” sorusu aklınıza geliyor. Jenkins için sağlam bir backup ve restore stratejisi kurmak, sadece iyi bir uygulama değil, production ortamında zorunluluktur.
Jenkins’in Dosya Yapısını Anlamak
Backup stratejisi oluşturmadan önce neyi yedekleyeceğimizi bilmemiz gerekiyor. Jenkins verilerinin tamamı JENKINS_HOME dizininde tutulur. Bu dizin genellikle /var/lib/jenkins ya da /opt/jenkins olarak bulunur, ama kuruluma göre farklılık gösterebilir.
# Jenkins home dizinini bulmak
echo $JENKINS_HOME
# ya da
systemctl show jenkins | grep JENKINS_HOME
# ya da doğrudan servis dosyasına bakın
cat /etc/default/jenkins | grep JENKINS_HOME
JENKINS_HOME altında kritik olan dizinler şunlardır:
- jobs/: Tüm job tanımlarınız ve build geçmişleri burada
- config.xml: Ana Jenkins konfigürasyonu
- credentials.xml: Tüm credential’larınız (şifreli olsa da backup’a dahil edin)
- plugins/: Yüklü plugin’ler
- users/: Kullanıcı hesapları ve API token’ları
- nodes/: Agent node konfigürasyonları
- secrets/: Şifreleme anahtarları (bu dizin olmadan credential’ları çözemezsiniz)
- fingerprints/: Artifact parmak izleri
- updates/: Plugin güncelleme bilgileri
Şunu özellikle vurgulamak istiyorum: secrets/ dizini olmadan yedeklediğiniz credential’lar tamamen işe yaramaz hale gelir. Çünkü Jenkins, credential’ları bu dizindeki anahtarlarla şifreler.
Basit Bash Script ile Manuel Backup
En temel yaklaşımdan başlayalım. Karmaşık araçlara geçmeden önce ne yaptığımızı anlamalıyız.
#!/bin/bash
# jenkins-backup.sh
JENKINS_HOME="/var/lib/jenkins"
BACKUP_DIR="/backup/jenkins"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="jenkins_backup_${DATE}"
LOG_FILE="/var/log/jenkins-backup.log"
# Log fonksiyonu
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Backup dizini oluştur
mkdir -p "${BACKUP_DIR}"
log "Jenkins backup başlıyor: ${BACKUP_NAME}"
# Jenkins servisini durdurmak zorunda değiliz ama tutarlılık için
# önerilen yol safe-restart ile beklemek
# Alternatif: quiet mode açıp mevcut build'lerin bitmesini beklemek
# Kritik dizinleri yedekle
tar -czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
--exclude="${JENKINS_HOME}/workspace"
--exclude="${JENKINS_HOME}/caches"
--exclude="${JENKINS_HOME}/logs"
--exclude="${JENKINS_HOME}/.git"
-C "$(dirname ${JENKINS_HOME})"
"$(basename ${JENKINS_HOME})"
if [ $? -eq 0 ]; then
log "Backup başarıyla tamamlandı: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
# Boyutu logla
SIZE=$(du -sh "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)
log "Backup boyutu: ${SIZE}"
else
log "HATA: Backup başarısız!"
exit 1
fi
# Eski backup'ları temizle (30 günden eski)
find "${BACKUP_DIR}" -name "jenkins_backup_*.tar.gz" -mtime +30 -delete
log "30 günden eski backup'lar temizlendi"
Bu script’i crontab’a ekleyerek otomatikleştirebilirsiniz:
# crontab -e ile ekleyin
# Her gün gece 02:00'de çalıştır
0 2 * * * /opt/scripts/jenkins-backup.sh
# Her 6 saatte bir çalıştır
0 */6 * * * /opt/scripts/jenkins-backup.sh
Workspace ve Build Geçmişini Hariç Tutmak
Prodüksiyonda çalışan bir Jenkins sunucusunda JENKINS_HOME kolayca 50-100GB’ı geçebilir. Bunun büyük çoğunluğu workspace’ler ve eski build loglarıdır. Bunları yedeklemeye gerek yoktur.
# Sadece kritik dosyaları yedekleyen daha seçici bir yaklaşım
tar -czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
--exclude="${JENKINS_HOME}/workspace/*"
--exclude="${JENKINS_HOME}/caches/*"
--exclude="${JENKINS_HOME}/logs/*"
--exclude="${JENKINS_HOME}/jobs/*/builds/*/archive"
--exclude="${JENKINS_HOME}/jobs/*/builds/*/log"
--exclude="${JENKINS_HOME}/jobs/*/htmlreports"
--exclude="${JENKINS_HOME}/war"
--exclude="${JENKINS_HOME}/.cache"
-C "$(dirname ${JENKINS_HOME})"
"$(basename ${JENKINS_HOME})"
Eğer build geçmişini de saklamak istiyorsanız ama disk alanından tasarruf etmek istiyorsanız, job konfigürasyonlarında “Discard old builds” ayarını aktif edin. Job başına maksimum 10-20 build tutmak genellikle yeterlidir.
ThinBackup Plugin ile Otomatik Backup
Jenkins’in en popüler backup plugin’i olan ThinBackup, arayüzden yönetilebilen güçlü bir çözüm sunar. Ama dikkatli olun, plugin’e tamamen bağımlı olmak bazı senaryolarda sorun çıkarabilir.
ThinBackup kurulumundan sonra Manage Jenkins > ThinBackup menüsünden konfigürasyon yapabilirsiniz. Script tabanlı yapılandırma tercih edenler için Groovy ile de ayarlayabilirsiniz:
// Jenkins Script Console'dan ThinBackup konfigürasyonu
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl
def thinBackup = ThinBackupPluginImpl.get()
thinBackup.setBackupPath('/backup/jenkins/thinbackup')
thinBackup.setFullBackupSchedule('0 2 * * 0') // Her Pazar gece 02:00
thinBackup.setDiffBackupSchedule('0 2 * * 1-6') // Hafta içi gece 02:00
thinBackup.setNrMaxStoredFull(4) // Maksimum 4 tam yedek
thinBackup.setExcludedFilesRegex('.*workspace.*')
thinBackup.setWaitForIdle(true)
thinBackup.save()
println "ThinBackup konfigürasyonu kaydedildi"
Jenkins Configuration as Code (JCasC) ile Backup Yaklaşımı
Modern Jenkins deployment’larında en sağlam yaklaşım, konfigürasyonu kod olarak yönetmektir. JCasC plugin’i kullanarak tüm Jenkins konfigürasyonunuzu YAML dosyasına dönüştürebilirsiniz.
# jenkins.yaml - JCasC konfigürasyon dosyası örneği
jenkins:
systemMessage: "Production Jenkins - DevOps Team"
numExecutors: 2
mode: NORMAL
securityRealm:
local:
allowsSignup: false
users:
- id: "admin"
password: "${ADMIN_PASSWORD}"
authorizationStrategy:
roleBased:
roles:
global:
- name: "admin"
permissions:
- "Overall/Administer"
assignments:
- "admin"
clouds:
- kubernetes:
name: "kubernetes"
serverUrl: "https://kubernetes.default"
namespace: "jenkins"
tool:
git:
installations:
- name: "Default"
home: "git"
unclassified:
location:
url: "https://jenkins.sirketiniz.com/"
adminAddress: "[email protected]"
Bu yaklaşımın güzelliği şu: Konfigürasyonunuz Git’te yaşıyor. Backup derdiniz yok, versiyon kontrolünüz var.
Restore İşlemi
Asıl test yedek almak değil, o yedeği geri yükleyebilmektir. Restore işlemini düzenli olarak test edin.
#!/bin/bash
# jenkins-restore.sh
BACKUP_FILE="$1"
JENKINS_HOME="/var/lib/jenkins"
JENKINS_USER="jenkins"
if [ -z "$BACKUP_FILE" ]; then
echo "Kullanım: $0 /backup/jenkins/jenkins_backup_20240115_020000.tar.gz"
exit 1
fi
if [ ! -f "$BACKUP_FILE" ]; then
echo "HATA: Backup dosyası bulunamadı: $BACKUP_FILE"
exit 1
fi
echo "Restore işlemi başlıyor..."
echo "Backup dosyası: $BACKUP_FILE"
# Jenkins servisini durdur
echo "Jenkins servisi durduruluyor..."
systemctl stop jenkins
# Mevcut konfigürasyonu yedekle (güvenlik için)
TEMP_BACKUP="/tmp/jenkins_pre_restore_$(date +%Y%m%d_%H%M%S)"
echo "Mevcut konfigürasyon geçici olarak yedekleniyor: $TEMP_BACKUP"
cp -r "$JENKINS_HOME" "$TEMP_BACKUP"
# JENKINS_HOME'u temizle (workspace'i koru)
echo "Jenkins home temizleniyor..."
find "$JENKINS_HOME" -mindepth 1 -maxdepth 1
! -name 'workspace'
-exec rm -rf {} +
# Backup'ı geri yükle
echo "Backup geri yükleniyor..."
tar -xzf "$BACKUP_FILE" -C "$(dirname $JENKINS_HOME)" --strip-components=1
# İzinleri düzelt
echo "İzinler düzenleniyor..."
chown -R "$JENKINS_USER:$JENKINS_USER" "$JENKINS_HOME"
chmod 700 "$JENKINS_HOME/secrets"
# Jenkins servisini başlat
echo "Jenkins servisi başlatılıyor..."
systemctl start jenkins
# Servisin başlamasını bekle
echo "Jenkins'in hazır olması bekleniyor..."
for i in {1..30}; do
if curl -sf http://localhost:8080/login > /dev/null 2>&1; then
echo "Jenkins başarıyla başladı!"
break
fi
echo "Bekleniyor... ($i/30)"
sleep 10
done
echo "Restore işlemi tamamlandı."
echo "Geçici backup: $TEMP_BACKUP (doğrulama sonrası silebilirsiniz)"
Uzak Sunucuya Backup Gönderme
Backup’ı aynı sunucuda tutmak, sunucu tamamen giderse işe yaramaz. Backup’ları uzak bir konuma göndermeliyiz.
#!/bin/bash
# jenkins-backup-remote.sh
JENKINS_HOME="/var/lib/jenkins"
LOCAL_BACKUP_DIR="/backup/jenkins"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="jenkins_backup_${DATE}.tar.gz"
REMOTE_SERVER="backup-server.sirket.local"
REMOTE_USER="backup"
REMOTE_DIR="/data/jenkins-backups"
S3_BUCKET="s3://sirket-jenkins-backups"
# Lokal backup oluştur
tar -czf "${LOCAL_BACKUP_DIR}/${BACKUP_NAME}"
--exclude="${JENKINS_HOME}/workspace"
--exclude="${JENKINS_HOME}/caches"
-C "$(dirname ${JENKINS_HOME})"
"$(basename ${JENKINS_HOME})"
# SCP ile uzak sunucuya gönder
echo "Uzak sunucuya gönderiliyor..."
scp -i /etc/jenkins/.ssh/backup_key
"${LOCAL_BACKUP_DIR}/${BACKUP_NAME}"
"${REMOTE_USER}@${REMOTE_SERVER}:${REMOTE_DIR}/"
# AWS S3'e yükle (aws cli kurulu olmalı)
if command -v aws &> /dev/null; then
echo "S3'e yükleniyor..."
aws s3 cp "${LOCAL_BACKUP_DIR}/${BACKUP_NAME}"
"${S3_BUCKET}/${BACKUP_NAME}"
--storage-class STANDARD_IA
# S3'te 90 günden eski dosyaları lifecycle policy ile silin
# ya da manuel:
# aws s3 ls ${S3_BUCKET} | awk '{print $4}' | head -n -90 | xargs -I{} aws s3 rm "${S3_BUCKET}/{}"
fi
# Lokal eski backup'ları temizle (7 gün)
find "${LOCAL_BACKUP_DIR}" -name "jenkins_backup_*.tar.gz" -mtime +7 -delete
echo "Backup ve transfer tamamlandı: ${BACKUP_NAME}"
Docker Tabanlı Jenkins için Backup
Eğer Jenkins’i Docker container olarak çalıştırıyorsanız, yaklaşım biraz farklı:
#!/bin/bash
# docker-jenkins-backup.sh
CONTAINER_NAME="jenkins"
BACKUP_DIR="/backup/jenkins"
DATE=$(date +%Y%m%d_%H%M%S)
# Volume mount noktasını bul
JENKINS_VOLUME=$(docker inspect "$CONTAINER_NAME"
--format='{{range .Mounts}}{{if eq .Destination "/var/jenkins_home"}}{{.Source}}{{end}}{{end}}')
echo "Jenkins volume: $JENKINS_VOLUME"
# Container'ı durdurma, çalışırken backup al
# Ama önce quiet mode'a al
docker exec "$CONTAINER_NAME"
curl -X POST http://localhost:8080/quietDown
--user "admin:${JENKINS_API_TOKEN}"
# Aktif build'lerin bitmesini bekle
sleep 30
# Backup al
tar -czf "${BACKUP_DIR}/jenkins_docker_${DATE}.tar.gz"
--exclude="${JENKINS_VOLUME}/workspace"
--exclude="${JENKINS_VOLUME}/caches"
-C "$(dirname $JENKINS_VOLUME)"
"$(basename $JENKINS_VOLUME)"
# Quiet mode'u kapat
docker exec "$CONTAINER_NAME"
curl -X POST http://localhost:8080/cancelQuietDown
--user "admin:${JENKINS_API_TOKEN}"
echo "Docker Jenkins backup tamamlandı"
Kubernetes’te Jenkins Backup (PVC Snapshot)
Kubernetes üzerinde Jenkins çalıştırıyorsanız, en temiz yol PersistentVolumeClaim snapshot’ı almaktır:
# jenkins-volume-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: jenkins-backup-20240115
namespace: jenkins
spec:
volumeSnapshotClassName: csi-aws-vsc
source:
persistentVolumeClaimName: jenkins-home-pvc
# Snapshot oluştur
kubectl apply -f jenkins-volume-snapshot.yaml
# Snapshot durumunu kontrol et
kubectl get volumesnapshot -n jenkins
# Snapshot'tan restore için yeni PVC oluştur
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-home-restored
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
dataSource:
name: jenkins-backup-20240115
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
EOF
Backup Doğrulama Script’i
Backup aldınız, peki işe yarar mı? Düzenli doğrulama yapmanız şart:
#!/bin/bash
# jenkins-backup-verify.sh
BACKUP_FILE="$1"
TEST_RESTORE_DIR="/tmp/jenkins-backup-test-$(date +%s)"
echo "Backup doğrulama başlıyor: $BACKUP_FILE"
# Arşiv bütünlüğünü kontrol et
echo "1. Arşiv bütünlüğü kontrol ediliyor..."
if tar -tzf "$BACKUP_FILE" > /dev/null 2>&1; then
echo " TAMAM: Arşiv bütünlüğü sağlam"
else
echo " HATA: Arşiv bozuk!"
exit 1
fi
# Test dizinine aç
echo "2. Test restore deneniyor..."
mkdir -p "$TEST_RESTORE_DIR"
tar -xzf "$BACKUP_FILE" -C "$TEST_RESTORE_DIR"
# Kritik dosyaların varlığını kontrol et
echo "3. Kritik dosyalar kontrol ediliyor..."
CRITICAL_FILES=(
"config.xml"
"credentials.xml"
"secrets/master.key"
"secrets/hudson.util.Secret"
)
RESTORE_HOME=$(find "$TEST_RESTORE_DIR" -name "config.xml" -maxdepth 3 | head -1 | xargs dirname)
for file in "${CRITICAL_FILES[@]}"; do
if [ -f "${RESTORE_HOME}/${file}" ]; then
echo " TAMAM: ${file} mevcut"
else
echo " UYARI: ${file} bulunamadı!"
fi
done
# Job sayısını kontrol et
JOB_COUNT=$(find "${RESTORE_HOME}/jobs" -name "config.xml" 2>/dev/null | wc -l)
echo "4. Yedeklenen job sayısı: $JOB_COUNT"
# Plugin sayısını kontrol et
PLUGIN_COUNT=$(find "${RESTORE_HOME}/plugins" -name "*.jpi" 2>/dev/null | wc -l)
echo "5. Yedeklenen plugin sayısı: $PLUGIN_COUNT"
# Temizlik
rm -rf "$TEST_RESTORE_DIR"
echo "Doğrulama tamamlandı."
Gerçek Dünya Senaryosu: Felaketten Dönüş
Geçen yıl bir müşterimin production Jenkins sunucusu, yapılan bir kernel güncellemesinin ardından bozuk dosya sistemiyle açılmaz hale geldi. Elimizde şanslı ki üç günlük backup vardı. Restore süreci şöyle işledi:
İlk adım olarak yeni bir sunucu ayağa kaldırdık ve aynı işletim sistemi versiyonunu, aynı Java versiyonunu ve aynı Jenkins versiyonunu kurduk. Bu önemli bir nokta: Farklı Jenkins versiyonuna restore etmeye çalışırsanız ciddi sorunlarla karşılaşabilirsiniz. Özellikle downgrade kesinlikle önerilmez.
İkinci adımda servisi başlatmadan backup’ı JENKINS_HOME üzerine açtık. Üçüncü adımda secrets/ dizininin doğru izinlere sahip olduğunu (chmod 700) doğruladık. Dördüncü adımda jenkins kullanıcısının tüm dosyalara sahipliğini kontrol ettik. Son olarak servisi başlattık ve tüm job’ların, pipeline’ların ve credential’ların yerli yerinde olduğunu gördük.
Toplam recovery süresi: 45 dakika. Backup olmasa en az 2 gün sürerdi.
Backup Stratejisi Önerileri
Sıfırdan bir strateji oluştururken şu noktaları göz önünde bulundurun:
- 3-2-1 kuralı: 3 kopya, 2 farklı medya, 1 off-site
- RPO (Recovery Point Objective): Ne kadar veri kaybı kabul edilebilir? Günlük backup ile maksimum 24 saatlik veri kaybı riski var
- RTO (Recovery Time Objective): Sistemi kaç saatte ayağa kaldırabilirsiniz?
- Backup’larınızı en az ayda bir test edin, tercihen her hafta
- Jenkins versiyonunu backup metadata’sına kaydedin
- Backup başarısız olduğunda alert alın, sessiz başarısızlık en tehlikeli senaryodur
- Credential backup’larını ayrı bir güvenli lokasyonda saklayın
- JCasC kullanıyorsanız Git repo’nuzun backup’ını da ihmal etmeyin
Sonuç
Jenkins backup stratejisi tek bir çözüme indirgenecek bir konu değil. Küçük bir ekip için günlük cron ile S3’e backup yeterli olabilirken, büyük bir CI/CD altyapısında JCasC + PVC snapshot + düzenli doğrulama kombinasyonu daha uygun olacaktır.
En önemli nokta şu: Backup almak sürecin yarısı, restore edebilmek diğer yarısı. “Felaket anında” ilk kez restore denemesi yapmak yerine, düzenli tatbikatlarla sürecinizi test edin. Sunucular yalnız gece yarısı bozulur ve o gece panik yaşamamak için bugünden hazırlıklı olun.
Workspace ve build log’larını dışarıda bırakarak, gerçekten önemli olan konfigürasyon dosyalarına odaklanın. Disk alanını verimli kullanın, doğrulama script’lerini cron’a ekleyin ve uyarılarınızı kurun. Jenkins’iniz ne kadar kritikse, backup stratejiniz o kadar sağlam olmalı.
