AWS S3 ile Statik İçerik Depolama ve Yönetimi

Bir web uygulaması geliştiriyorsunuz, kullanıcılar dosya yüklüyor, sitenizde görseller var ve her geçen gün depolama ihtiyacınız artıyor. Kendi sunucunuzda disk yönetmek, yedek almak, erişim kontrolü kurmak… Bunların hepsi zaman ve kaynak isteyen işler. İşte tam bu noktada AWS S3 devreye giriyor. S3, yani Simple Storage Service, bugün dünya üzerinde milyonlarca uygulamanın güvendiği nesne depolama servisi. Bu yazıda S3’ü sıfırdan alıp production ortamınıza nasıl entegre edersiniz, hangi noktalara dikkat etmeniz gerekir, gerçek dünya senaryolarıyla birlikte detaylıca konuşacağız.

AWS S3 Nedir ve Neden Kullanmalısınız

S3, nesne tabanlı bir depolama servisidir. Geleneksel dosya sistemlerinden farklı olarak verilerinizi “bucket” adı verilen kaplarda “object” olarak saklarsınız. Her nesnenin bir anahtarı (key), verisi ve metadata’sı vardır. Bu mimarinin güzelliği şu: teorik olarak sınırsız veri saklayabilirsiniz, 99.999999999% (11 dokuz) dayanıklılık garantisi var ve verileriniz otomatik olarak birden fazla lokasyona kopyalanıyor.

Bir sysadmin olarak beni en çok etkileyen şey şu: disk doldu diye gece 3’te kalkmak yok. Kapasite planlaması derdi yok. Siz sadece verinizi koyuyorsunuz, S3 gerisini hallediyor.

Statik içerik depolama için S3’ü tercih etmenin somut nedenleri:

  • Maliyet etkinliği: Kendi sunucunuzda SSD/HDD masrafı yerine kullandığın kadar öde modeli
  • Yüksek erişilebilirlik: Multi-AZ replikasyon kutudan çıktığı gibi geliyor
  • CDN entegrasyonu: CloudFront ile tek tıkla global dağıtım
  • Versiyon kontrolü: Dosyalarınızın geçmiş versiyonlarını tutabilirsiniz
  • Yaşam döngüsü politikaları: Eski dosyaları otomatik olarak daha ucuz storage class’lara taşıyabilirsiniz

AWS CLI Kurulumu ve Yapılandırması

Öncelikle makinenize AWS CLI kurmanız gerekiyor. Bu olmadan terminalden hiçbir şey yapamazsınız.

# Linux için AWS CLI v2 kurulumu
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Kurulumu doğrula
aws --version

Kurulum sonrası credentials yapılandırması yapmanız şart. IAM kullanıcısı oluşturup access key alın, root kullanıcıyla çalışmayın asla.

# Interaktif yapılandırma
aws configure

# Şu bilgileri soracak:
# AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Default region name [None]: eu-west-1
# Default output format [None]: json

Birden fazla AWS hesabıyla çalışıyorsanız, profil sistemi kullanın. Bu çok işinize yarayacak.

# Farklı profil oluşturma
aws configure --profile production
aws configure --profile staging

# Profil kullanarak komut çalıştırma
aws s3 ls --profile production

# Varsayılan profili environment variable ile set etme
export AWS_PROFILE=production

İlk Bucket’ı Oluşturmak

Bucket isimleri global olarak benzersiz olmak zorunda. Yani “my-bucket” diye bir bucket zaten varsa, siz de aynı ismi kullanamazsınız. Bu yüzden genellikle şirket adı, proje adı ve ortam bilgisini birleştirmek iyi bir pratik.

# Bucket oluşturma (eu-central-1 Frankfurt bölgesi)
aws s3api create-bucket 
    --bucket mycompany-webapp-static-prod 
    --region eu-central-1 
    --create-bucket-configuration LocationConstraint=eu-central-1

# Bucket listesini görme
aws s3 ls

# Bucket içeriğini listeleme
aws s3 ls s3://mycompany-webapp-static-prod/

# Recursive listeleme (alt klasörlerle birlikte)
aws s3 ls s3://mycompany-webapp-static-prod/ --recursive

Bucket oluşturduktan sonra versioning’i açın. Bu özelliği baştan açmazsanız, sonradan pişman olabilirsiniz. Yanlışlıkla silinen bir dosyayı geri getirmek istediğinizde versioning yoksa yapabileceğiniz hiçbir şey kalmıyor.

# Versioning'i aktif etme
aws s3api put-bucket-versioning 
    --bucket mycompany-webapp-static-prod 
    --versioning-configuration Status=Enabled

# Versioning durumunu kontrol etme
aws s3api get-bucket-versioning 
    --bucket mycompany-webapp-static-prod

Dosya Yükleme ve Yönetme

S3 CLI komutları oldukça sezgisel. cp, mv, rm gibi tanıdık komutlar var. Ancak arka planda nesne depolama olduğunu unutmayın, gerçek anlamda klasör yok, sadece key prefix’leri var.

# Tek dosya yükleme
aws s3 cp logo.png s3://mycompany-webapp-static-prod/images/logo.png

# Metadata ile birlikte yükleme (cache-control önemli!)
aws s3 cp logo.png s3://mycompany-webapp-static-prod/images/logo.png 
    --cache-control "max-age=31536000" 
    --content-type "image/png"

# Dizin senkronizasyonu (en çok kullandığım komut)
aws s3 sync ./dist/ s3://mycompany-webapp-static-prod/ 
    --delete 
    --exclude "*.DS_Store" 
    --exclude ".git/*"

# HTML dosyaları için farklı cache ayarı
aws s3 sync ./dist/ s3://mycompany-webapp-static-prod/ 
    --exclude "*" 
    --include "*.html" 
    --cache-control "no-cache, no-store, must-revalidate" 
    --metadata-directive REPLACE

# Büyük dosyalar için multipart upload (paralel upload ile hız artışı)
aws s3 cp large-video.mp4 s3://mycompany-webapp-static-prod/videos/ 
    --multipart-threshold 64MB 
    --multipart-chunksize 16MB

sync komutu deployment senaryolarında altın değerinde. Sadece değişen dosyaları yükler, bu da CI/CD pipeline’larınızı çok hızlandırır.

Erişim Kontrolü ve Güvenlik

S3 güvenliği çok katmanlı bir yapıya sahip ve bu katmanları anlamak kritik. Bucket policy, ACL, IAM policy ve S3 Block Public Access… Bunların hepsi birlikte çalışıyor.

2023 itibarıyla AWS’nin varsayılanı tüm public erişimi engellemek. Bu iyi bir şey. Statik web sitesi sunuyorsanız ve herkesin erişmesini istiyorsanız, bunu bilinçli olarak açmanız gerekiyor.

# Block Public Access ayarlarını görme
aws s3api get-public-access-block 
    --bucket mycompany-webapp-static-prod

# Public erişime izin verme (statik web sitesi için)
aws s3api put-public-access-block 
    --bucket mycompany-webapp-static-prod 
    --public-access-block-configuration 
    "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"

Bucket policy ile ince taneli erişim kontrolü yapabilirsiniz. Örneğin sadece belirli bir IP aralığından okumaya izin vermek, ya da sadece CloudFront üzerinden erişimi zorunlu kılmak gibi.

# Bucket policy oluşturma ve uygulama
cat > bucket-policy.json << 'EOF'
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mycompany-webapp-static-prod/*"
        }
    ]
}
EOF

aws s3api put-bucket-policy 
    --bucket mycompany-webapp-static-prod 
    --policy file://bucket-policy.json

IAM tarafında ise uygulamanıza minimum gerekli izinleri verin. Örneğin sadece okuma yapacak bir uygulama için s3:GetObject yeterli, s3:DeleteObject vermek mantıklı değil.

Statik Web Sitesi Olarak S3 Kullanmak

S3’ün güzel özelliklerinden biri doğrudan statik web sitesi sunabilmesi. React, Vue, Angular gibi frameworklerle ürettiğiniz build çıktısını S3’e atıp servis edebilirsiniz.

# Statik web sitesi hosting'i aktif etme
aws s3api put-bucket-website 
    --bucket mycompany-webapp-static-prod 
    --website-configuration '{
        "IndexDocument": {"Suffix": "index.html"},
        "ErrorDocument": {"Key": "error.html"}
    }'

# Web sitesi endpoint'ini öğrenme
aws s3api get-bucket-website 
    --bucket mycompany-webapp-static-prod

# Website URL formatı şöyle olur:
# http://mycompany-webapp-static-prod.s3-website.eu-central-1.amazonaws.com

SPA (Single Page Application) kullanıyorsanız routing için bir ayar yapmanız gerekiyor. React Router gibi client-side routing kullanan uygulamalarda, kullanıcı doğrudan /about sayfasına giderse S3 bu dosyayı bulamaz ve 404 döner. Çözüm: error document olarak index.html set etmek.

# SPA için error document'ı index.html yap
aws s3api put-bucket-website 
    --bucket mycompany-webapp-static-prod 
    --website-configuration '{
        "IndexDocument": {"Suffix": "index.html"},
        "ErrorDocument": {"Key": "index.html"}
    }'

Bu yöntemde HTTP 404 yerine 200 dönmesi gerekiyor aslında ama basit senaryolar için çalışır. Daha temiz çözüm için CloudFront kullanmanızı öneririm.

Yaşam Döngüsü Politikaları

Bu özellik maliyet optimizasyonu açısından çok değerli. Örneğin log dosyalarınızı 30 gün sonra daha ucuz bir storage class’a taşıyabilir, 90 gün sonra silebilirsiniz. Ya da uygulama build artifact’larını belirli süre sonra temizleyebilirsiniz.

# Yaşam döngüsü politikası uygulama
cat > lifecycle-policy.json << 'EOF'
{
    "Rules": [
        {
            "ID": "LogArchiveAndDelete",
            "Status": "Enabled",
            "Filter": {
                "Prefix": "logs/"
            },
            "Transitions": [
                {
                    "Days": 30,
                    "StorageClass": "STANDARD_IA"
                },
                {
                    "Days": 60,
                    "StorageClass": "GLACIER"
                }
            ],
            "Expiration": {
                "Days": 365
            }
        },
        {
            "ID": "CleanOldVersions",
            "Status": "Enabled",
            "Filter": {"Prefix": ""},
            "NoncurrentVersionExpiration": {
                "NoncurrentDays": 30
            }
        }
    ]
}
EOF

aws s3api put-bucket-lifecycle-configuration 
    --bucket mycompany-webapp-static-prod 
    --lifecycle-configuration file://lifecycle-policy.json

Storage class’lar hakkında kısa özet:

  • S3 Standard: Sık erişilen veriler için, en yüksek performans
  • S3 Standard-IA: Ayda bir iki kez erişilen veriler, daha ucuz depolama ama erişim maliyeti var
  • S3 Glacier Instant Retrieval: Arşiv ama milisaniyede erişim
  • S3 Glacier: Gerçek arşiv, saatler içinde erişim, çok ucuz
  • S3 Glacier Deep Archive: En ucuzu, 12 saate kadar erişim süresi

Gerçek Dünya Senaryosu: CI/CD ile Otomatik Deployment

Bir e-ticaret sitesi düşünün. Her deploy’da React build’ı S3’e atmanız gerekiyor. Şu script’i CI/CD pipeline’ınıza ekleyebilirsiniz:

#!/bin/bash
set -e

BUCKET="mycompany-webapp-static-prod"
BUILD_DIR="./dist"
CLOUDFRONT_DISTRIBUTION_ID="E1234567890ABC"

echo "Build başlıyor..."
npm run build

echo "HTML dosyaları yükleniyor (no-cache)..."
aws s3 sync "$BUILD_DIR" "s3://$BUCKET" 
    --exclude "*" 
    --include "*.html" 
    --cache-control "no-cache, no-store, must-revalidate" 
    --content-type "text/html; charset=utf-8" 
    --delete 
    --metadata-directive REPLACE

echo "Static asset'ler yükleniyor (1 yıl cache)..."
aws s3 sync "$BUILD_DIR" "s3://$BUCKET" 
    --exclude "*.html" 
    --cache-control "public, max-age=31536000, immutable" 
    --delete

echo "CloudFront cache invalidation yapılıyor..."
aws cloudfront create-invalidation 
    --distribution-id "$CLOUDFRONT_DISTRIBUTION_ID" 
    --paths "/*.html" "/index.html"

echo "Deployment tamamlandı!"

Bu script’te iki ayrı sync yapıyoruz: HTML dosyaları için no-cache (her zaman taze içerik), JS/CSS/resim gibi statik asset’ler için 1 yıl cache. Bu web performansının temel pratiğidir.

S3 Transfer Acceleration

Küresel kullanıcı kitleniz varsa ve dosya yükleme hızı önemliyse Transfer Acceleration özelliğine bakın. Bu özellik AWS’nin CloudFront edge location’larını kullanarak upload hızını artırıyor.

# Transfer Acceleration aktif etme
aws s3api put-bucket-accelerate-configuration 
    --bucket mycompany-webapp-static-prod 
    --accelerate-configuration Status=Enabled

# Accelerated endpoint kullanımı
aws s3 cp largefile.zip 
    s3://mycompany-webapp-static-prod/ 
    --endpoint-url https://s3-accelerate.amazonaws.com

# Hız testini yapmak için
aws s3 cp /dev/stdin 
    s3://mycompany-webapp-static-prod/test-upload.txt 
    --endpoint-url https://s3-accelerate.dualstack.amazonaws.com <<< "test"

Monitoring ve Maliyet Takibi

S3 maliyetleri düşük görünse de büyük hacimlerde fark yaratıyor. CloudWatch ile request metriklerini takip edin, beklenmedik spike’ları yakalayın.

# Bucket boyutunu öğrenme
aws cloudwatch get-metric-statistics 
    --namespace AWS/S3 
    --metric-name BucketSizeBytes 
    --dimensions Name=BucketName,Value=mycompany-webapp-static-prod 
                 Name=StorageType,Value=StandardStorage 
    --start-time 2024-01-01T00:00:00Z 
    --end-time 2024-01-02T00:00:00Z 
    --period 86400 
    --statistics Average

# Nesne sayısını öğrenme
aws cloudwatch get-metric-statistics 
    --namespace AWS/S3 
    --metric-name NumberOfObjects 
    --dimensions Name=BucketName,Value=mycompany-webapp-static-prod 
                 Name=StorageType,Value=AllStorageTypes 
    --start-time 2024-01-01T00:00:00Z 
    --end-time 2024-01-02T00:00:00Z 
    --period 86400 
    --statistics Average

# Tüm bucket'ların toplam boyutunu hesaplamak için
aws s3api list-buckets --query 'Buckets[].Name' --output text | 
tr 't' 'n' | 
while read bucket; do
    size=$(aws s3 ls s3://$bucket --recursive --summarize 2>/dev/null | 
           grep "Total Size" | awk '{print $3}')
    echo "$bucket: $size bytes"
done

Maliyet optimizasyonu için birkaç pratik öneri:

  • S3 Intelligent-Tiering kullanın: Erişim pattern’inizi bilmiyorsanız, bu storage class otomatik olarak doğru tier’a taşıyor
  • Request sayısını minimize edin: Çok sayıda küçük dosya yerine bundle’lar kullanın
  • Incomplete multipart upload’ları temizleyin: Bunlar ücret oluşturuyor ama görünmüyor
  • Server access logging’i sadece gerektiğinde açın: Log dosyaları da ücrete tabi
  • Bölge seçimine dikkat edin: Kullanıcılarınızın yakınındaki region’ı seçmek veri transfer maliyetini düşürür

Encryption ve Compliance

Production ortamında şifreleme şart. S3 server-side encryption için birkaç seçenek var:

  • SSE-S3: S3’ün kendi anahtarlarıyla şifreleme, basit ve ücretsiz
  • SSE-KMS: AWS KMS anahtarlarıyla şifreleme, denetim izi var, küçük ek maliyet
  • SSE-C: Kendi anahtarlarınızla şifreleme, anahtar yönetimi size ait
# Varsayılan şifrelemeyi aktif etme (SSE-S3)
aws s3api put-bucket-encryption 
    --bucket mycompany-webapp-static-prod 
    --server-side-encryption-configuration '{
        "Rules": [{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
            },
            "BucketKeyEnabled": true
        }]
    }'

# KMS ile şifreleme (daha fazla kontrol)
aws s3api put-bucket-encryption 
    --bucket mycompany-webapp-static-prod 
    --server-side-encryption-configuration '{
        "Rules": [{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "aws:kms",
                "KMSMasterKeyID": "arn:aws:kms:eu-central-1:123456789:key/your-key-id"
            },
            "BucketKeyEnabled": true
        }]
    }'

# Şifreleme konfigürasyonunu doğrulama
aws s3api get-bucket-encryption 
    --bucket mycompany-webapp-static-prod

Sık Yapılan Hatalar ve Çözümleri

Yıllar içinde gördüğüm en yaygın S3 hatalarından bahsedelim.

Public bucket’ı yanlışlıkla çok açık bırakmak: Sadece s3:GetObject yetki verin, listelemeyı kapatın. s3:ListBucket izni olan biri tüm dosyalarınızı görebilir, bu genellikle istemediğiniz bir şey.

Cache-Control header’ı ayarlamamak: S3’ten sunulan dosyalarda cache header yoksa tarayıcı her seferinde dosyayı tekrar çekiyor. Statik asset’ler için max-age=31536000 immutable kullanın.

Bölge uyumsuzluğu: Uygulamanız Frankfurt’ta çalışırken bucket’ınız Oregon’daysa veri transfer maliyeti ve gecikme oluşur. Aynı bölgede tutun.

Versioning açmadan kritik veriyi saklamak: “Nasılsa silmem” diye düşünmeyin. Yanlışlıkla silme senaryosu her zaman olabilir. Versioning açık olsun.

IAM yerine ACL kullanmak: ACL eski bir yöntem, karmaşık ve yönetimi zor. IAM policy ve bucket policy kombinasyonunu tercih edin.

Sonuç

AWS S3, statik içerik yönetimi için gerçekten sağlam bir altyapı sunuyor. Başlangıçta biraz öğrenme eğrisi var: IAM, bucket policy, storage class’lar, lifecycle… Ama bir kez oturttuğunuzda günlerce size vakit kazandırıyor.

Özetlemek gerekirse: bucket oluştururken versioning’i açın, şifrelemeyi varsayılan yapın, minimum yetki prensibini uygulayın ve lifecycle politikalarıyla maliyetinizi optimize edin. Statik web sitesi için CloudFront’u S3’ün önüne koyun, hem performans hem de güvenlik kazanırsınız.

CI/CD entegrasyonunu kurduğunuzda ise işin güzelliğini tam anlıyorsunuz: kodu push ediyorsunuz, pipeline build alıyor, S3’e deploy ediyor, CloudFront invalidation yapıyor. Siz kahvenizi içiyorsunuz. Sistem yönetimi böyle olmalı.

Bir yanıt yazın

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