AWS S3 Versioning ve Yaşam Döngüsü Kuralları ile Depolama Yönetimi

Üretim ortamında bir S3 bucket’ından yanlışlıkla silinen dosyaları geri getirmeye çalıştığınız o kaotik anı hayal edin. Ekip panik halinde, müşteri verisi kaybolmuş olabilir ve siz orada “keşke versioning açık olsaydı” diye düşünüyorsunuz. Bu senaryoyu yaşamamak için S3 Versioning ve Lifecycle kurallarını doğru yapılandırmak, AWS üzerinde çalışan her sysadmin’in temel sorumluluklarından biridir. Bu yazıda hem versioning’in derinliklerine ineceğiz hem de lifecycle kurallarıyla maliyetleri nasıl kontrol altında tutacağınızı pratik örneklerle ele alacağız.

S3 Versioning Nedir ve Neden Önemlidir

S3 Versioning, bir bucket içindeki her nesnenin birden fazla sürümünü saklamanızı sağlar. Bir dosyayı üzerine yazdığınızda veya sildiğinizde, eski sürüm kaybolmaz; yeni bir sürüm ID’siyle birlikte depoda tutulmaya devam eder. Bu mekanizma sayesinde hem yanlışlıkla yapılan silme işlemlerinden hem de veri bozulmalarından korunmuş olursunuz.

Versioning açık olan bir bucket’ta silme işlemi gerçekleştirdiğinizde, S3 dosyayı fiziksel olarak silmez. Bunun yerine “delete marker” adı verilen özel bir işaretçi ekler. Bu işaretçiyi kaldırdığınızda dosya sanki hiç silinmemiş gibi geri gelir. Prodüksiyonda bu fark hayat kurtarıcı olabilir.

Versioning’in getirdiği üç temel koruma mekanizması şunlardır:

  • Yanlışlıkla silme koruması: Delete marker mekanizması sayesinde veriler fiziksel olarak silinmez
  • Üzerine yazma koruması: Her PUT işlemi yeni bir versiyon oluşturur, eski sürümler korunur
  • Uygulama hatası koruması: Bozuk veri yazıldığında önceki sürüme dönmek mümkündür

Versioning Nasıl Etkinleştirilir

AWS CLI üzerinden versioning’i etkinleştirmek oldukça basittir. Önce mevcut durumu kontrol edelim:

# Bucket'ın versioning durumunu kontrol et
aws s3api get-bucket-versioning 
  --bucket my-production-bucket

# Versioning'i etkinleştir
aws s3api put-bucket-versioning 
  --bucket my-production-bucket 
  --versioning-configuration Status=Enabled

# MFA Delete ile birlikte etkinleştirme (daha güvenli)
aws s3api put-bucket-versioning 
  --bucket my-production-bucket 
  --versioning-configuration Status=Enabled,MFADelete=Enabled 
  --mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"

Versioning etkinleştirildikten sonra bucket’taki mevcut nesneler “null” versiyon ID’sine sahip olur. Yeni yüklenen veya güncellenen dosyalar ise benzersiz bir versiyon ID’si alır.

Versiyonları Yönetmek

Versioning aktif bir bucket’ta çalışırken bilmeniz gereken birkaç temel komut var:

# Belirli bir nesnenin tüm versiyonlarını listele
aws s3api list-object-versions 
  --bucket my-production-bucket 
  --prefix "backups/database.sql"

# Belirli bir versiyonu indir
aws s3api get-object 
  --bucket my-production-bucket 
  --key "backups/database.sql" 
  --version-id "Kb47DRCEhkbWMKL9jYM8OqnlhO3.EXAMPLE" 
  restored_database.sql

# Delete marker'ları listele
aws s3api list-object-versions 
  --bucket my-production-bucket 
  --query "DeleteMarkers[*].{Key:Key,VersionId:VersionId,LastModified:LastModified}"

Gerçek dünya senaryosu: Bir uygulama güncellemesi sırasında yanlış konfigürasyon dosyası S3’e yazıldı ve servis çöktü. Versioning açık olduğunda çözüm şu kadar basit:

# Hangi versiyon önceki çalışan sürümdü, bul
aws s3api list-object-versions 
  --bucket my-production-bucket 
  --prefix "config/app.json" 
  --query "Versions[*].{VersionId:VersionId,LastModified:LastModified,IsLatest:IsLatest}"

# Önceki versiyonu geri yükle (eski versiyonu tekrar yükleyerek)
aws s3api copy-object 
  --bucket my-production-bucket 
  --copy-source "my-production-bucket/config/app.json?versionId=abc123EXAMPLE" 
  --key "config/app.json"

Toplu Versiyon Temizleme

Versioning açık bıraktıysanız ve lifecycle kuralı koymadıysanız, bucket boyutunuz hızla şişer. Özellikle sık güncellenen dosyaların onlarca versiyonu birikerek depolama maliyetlerinizi katlayabilir. Bu durumda belirli kriterlere göre eski versiyonları temizlemek gerekir:

#!/bin/bash
# Belirli bir prefix altındaki 30 günden eski versiyonları sil
BUCKET="my-production-bucket"
PREFIX="logs/"
DAYS_OLD=30

# Eski versiyonları bul ve sil
aws s3api list-object-versions 
  --bucket "$BUCKET" 
  --prefix "$PREFIX" 
  --query "Versions[?LastModified<='$(date -d "$DAYS_OLD days ago" --utc +%Y-%m-%dT%H:%M:%SZ)'].{Key:Key,VersionId:VersionId}" 
  --output json | 
jq -r '.[] | "--key (.Key) --version-id (.VersionId)"' | 
while read params; do
  aws s3api delete-object --bucket "$BUCKET" $params
  echo "Silindi: $params"
done

Bu scripti cron’a ekleyebilir ya da AWS Lambda üzerinde otomatik çalıştırabilirsiniz. Ancak daha temiz ve yönetilebilir bir çözüm için lifecycle kuralları devreye girer.

S3 Lifecycle Kuralları

Lifecycle kuralları, nesnelerin yaşam döngüsünü otomatik olarak yönetmenizi sağlar. Belirli bir süre sonra nesneleri daha ucuz depolama sınıflarına taşıyabilir, eski versiyonları otomatik silebilir veya tamamlanmamış multipart upload’ları temizleyebilirsiniz.

Lifecycle kurallarıyla yapabilecekleriniz:

  • Transition: Nesneleri S3 Standard’dan Infrequent Access, Glacier veya Glacier Deep Archive’a taşı
  • Expiration: Nesneleri belirli bir süre sonra otomatik sil
  • NoncurrentVersionExpiration: Eski versiyonları otomatik sil
  • AbortIncompleteMultipartUpload: Yarım kalan yüklemeleri temizle
  • NoncurrentVersionTransition: Eski versiyonları daha ucuz depolama sınıflarına taşı

Temel Lifecycle Kuralı Oluşturma

JSON formatında bir lifecycle politikası oluşturalım. Bu örnekte log dosyaları için gerçekçi bir senaryo kullanacağız:

# lifecycle-policy.json dosyası oluştur
cat > lifecycle-policy.json << 'EOF'
{
  "Rules": [
    {
      "ID": "log-files-lifecycle",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "logs/"
      },
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        },
        {
          "Days": 365,
          "StorageClass": "DEEP_ARCHIVE"
        }
      ],
      "Expiration": {
        "Days": 730
      },
      "NoncurrentVersionTransitions": [
        {
          "NoncurrentDays": 30,
          "StorageClass": "GLACIER"
        }
      ],
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 90
      },
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 7
      }
    }
  ]
}
EOF

# Politikayı uygula
aws s3api put-bucket-lifecycle-configuration 
  --bucket my-production-bucket 
  --lifecycle-configuration file://lifecycle-policy.json

# Mevcut lifecycle kurallarını görüntüle
aws s3api get-bucket-lifecycle-configuration 
  --bucket my-production-bucket

Çoklu Kural Senaryosu: Gerçek Dünya Örneği

Bir e-ticaret şirketinde çalıştığınızı düşünün. Bucket’ınızda birden fazla farklı içerik türü var: kullanıcı yüklediği görseller, sistem logları, veritabanı yedekleri ve geçici işlem dosyaları. Her biri için farklı lifecycle kuralı gerekiyor:

cat > ecommerce-lifecycle.json << 'EOF'
{
  "Rules": [
    {
      "ID": "user-images-policy",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "user-uploads/images/"
      },
      "Transitions": [
        {
          "Days": 180,
          "StorageClass": "STANDARD_IA"
        }
      ],
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 30
      }
    },
    {
      "ID": "database-backups-policy",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "backups/database/"
      },
      "Transitions": [
        {
          "Days": 7,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 30,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 365
      },
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 7
      }
    },
    {
      "ID": "temp-files-cleanup",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "temp/"
      },
      "Expiration": {
        "Days": 1
      },
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 1
      }
    },
    {
      "ID": "system-logs-archive",
      "Status": "Enabled",
      "Filter": {
        "And": {
          "Prefix": "logs/system/",
          "Tags": [
            {
              "Key": "environment",
              "Value": "production"
            }
          ]
        }
      },
      "Transitions": [
        {
          "Days": 14,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 60,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 545
      }
    }
  ]
}
EOF

aws s3api put-bucket-lifecycle-configuration 
  --bucket my-ecommerce-bucket 
  --lifecycle-configuration file://ecommerce-lifecycle.json

Maliyet Optimizasyonu: Depolama Sınıfları

Lifecycle kurallarını doğru kurgulamak için depolama sınıflarını anlamak şart. Kısaca özetlemek gerekirse:

  • S3 Standard: Sık erişilen veriler için, en yüksek maliyet
  • S3 Standard-IA (Infrequent Access): Aylık birkaç kez erişilen veriler, Standard’dan %40 ucuz
  • S3 One Zone-IA: Tek AZ’da, IA’dan %20 daha ucuz ama daha az dayanıklı
  • S3 Glacier Instant Retrieval: Arşiv ama anında erişim gerektiğinde
  • S3 Glacier Flexible Retrieval: Dakikalar ile saatler içinde erişim
  • S3 Glacier Deep Archive: En ucuz, 12-48 saat erişim süresi, uzun süreli arşivler için

Intelligent-Tiering kullanmak da bir seçenek olabilir. Erişim paternleri tahmin edilemez olan veriler için AWS otomatik olarak en uygun katmana taşır:

# Intelligent-Tiering konfigürasyonu
aws s3api put-bucket-intelligent-tiering-configuration 
  --bucket my-production-bucket 
  --id "EntireS3BucketIT" 
  --intelligent-tiering-configuration 
'{
  "Id": "EntireS3BucketIT",
  "Status": "Enabled",
  "Tierings": [
    {
      "Days": 90,
      "AccessTier": "ARCHIVE_ACCESS"
    },
    {
      "Days": 180,
      "AccessTier": "DEEP_ARCHIVE_ACCESS"
    }
  ]
}'

Lifecycle Kurallarını İzleme ve Doğrulama

Lifecycle kuralları uygulandıktan sonra işe yarayıp yaramadığını nasıl doğrularsınız? S3 Storage Lens ve CloudWatch metrikleri burada devreye girer:

# S3 Storage Lens raporu oluştur
aws s3control create-storage-lens-configuration 
  --account-id 123456789012 
  --config-id "lifecycle-monitoring" 
  --storage-lens-configuration 
'{
  "Id": "lifecycle-monitoring",
  "IsEnabled": true,
  "AccountLevel": {
    "BucketLevel": {
      "ActivityMetrics": {
        "IsEnabled": true
      }
    }
  },
  "DataExport": {
    "S3BucketDestination": {
      "AccountId": "123456789012",
      "Arn": "arn:aws:s3:::my-lens-reports-bucket",
      "Format": "CSV",
      "OutputSchemaVersion": "V_1"
    }
  }
}'

# Bucket bazında nesne sayısı ve boyut istatistiklerini al
aws cloudwatch get-metric-statistics 
  --namespace AWS/S3 
  --metric-name BucketSizeBytes 
  --dimensions Name=BucketName,Value=my-production-bucket 
               Name=StorageType,Value=StandardStorage 
  --start-time 2024-01-01T00:00:00Z 
  --end-time 2024-01-31T00:00:00Z 
  --period 86400 
  --statistics Average

Terraform ile Lifecycle Yönetimi

Elle JSON yazmak yerine Terraform kullanıyorsanız, lifecycle kurallarını kod olarak yönetmek çok daha sürdürülebilir olur:

# terraform apply ile uygulanabilecek S3 lifecycle konfigürasyonu
# main.tf içeriği - bash bloku olarak gösteriliyor

cat > main.tf << 'TERRAFORM'
resource "aws_s3_bucket_versioning" "production" {
  bucket = aws_s3_bucket.production.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "production" {
  bucket = aws_s3_bucket.production.id
  
  depends_on = [aws_s3_bucket_versioning.production]

  rule {
    id     = "application-logs"
    status = "Enabled"

    filter {
      prefix = "logs/app/"
    }

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = 90
      storage_class = "GLACIER"
    }

    expiration {
      days = 365
    }

    noncurrent_version_expiration {
      noncurrent_days = 30
    }

    abort_incomplete_multipart_upload {
      days_after_initiation = 7
    }
  }

  rule {
    id     = "database-backups"
    status = "Enabled"

    filter {
      prefix = "backups/"
    }

    transition {
      days          = 7
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = 30
      storage_class = "GLACIER"
    }

    noncurrent_version_transition {
      noncurrent_days = 7
      storage_class   = "GLACIER"
    }

    noncurrent_version_expiration {
      noncurrent_days = 90
    }
  }
}
TERRAFORM

terraform init && terraform plan

Yaygın Hatalar ve Dikkat Edilmesi Gerekenler

Versioning ve lifecycle kurallarını uygularken karşılaşılan tipik sorunlar:

  • Delete marker birikimi: Lifecycle kuralınızda ExpiredObjectDeleteMarker: true eklemezseniz, silinen dosyaların bıraktığı işaretçiler bucket’ı şişirir
  • Minimum depolama süresi: STANDARD_IA için minimum 30 gün, Glacier için 90 gün, Deep Archive için 180 gün ücretlendirilirsiniz. Erken taşıma maliyet artırabilir
  • Versioning askıya alma: Versioning’i “Suspended” yaparsanız yeni nesneler versiyon almaz ama eski versiyonlar silinmez, hala ücretlendirilirsiniz
  • Çakışan kurallar: Aynı prefix’i kapsayan birden fazla kural tanımlandığında beklenmedik davranışlar oluşabilir
  • Lifecycle gecikmesi: Kurallar genellikle midnight UTC’de çalışır, anlık değildir. 24-48 saat gecikme normal kabul edilir

Delete marker temizliği için lifecycle konfigürasyonunuza şunu eklemeyi unutmayın:

# Delete marker temizleme kuralı ekle
cat > cleanup-rule.json << 'EOF'
{
  "Rules": [
    {
      "ID": "cleanup-expired-markers",
      "Status": "Enabled",
      "Filter": {
        "Prefix": ""
      },
      "Expiration": {
        "ExpiredObjectDeleteMarker": true
      }
    }
  ]
}
EOF

Sonuç

S3 Versioning ve Lifecycle kuralları birbirini tamamlayan iki mekanizmadır. Versioning olmadan lifecycle kuralları yalnızca maliyet optimizasyonu aracına dönüşür; lifecycle olmadan versioning ise depolama maliyetlerinizi kontrolden çıkarır. İkisini birlikte ve doğru yapılandırdığınızda hem veri güvenliğini garanti altına alırsınız hem de gereksiz harcamaların önüne geçersiniz.

Pratikte önerim şu: Her yeni bucket oluşturduğunuzda versioning’i varsayılan olarak açın, sonra içerik tipine ve erişim paternine göre lifecycle kurallarını tanımlayın. Bu yapıyı Terraform gibi bir IaC aracıyla kodlaştırırsanız, her ortamda tutarlı ve denetlenebilir bir yapı elde edersiniz. Maliyetlerinizi düzenli olarak S3 Storage Lens raporlarıyla takip edin ve lifecycle kurallarınızı gerçek kullanım paternlerine göre revize etmekten çekinmeyin. Bulut maliyeti yönetimi tek seferlik değil, sürekli bir süreçtir.

Bir yanıt yazın

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