AWS EC2 AMI Oluşturma ve Yönetimi: Kapsamlı Rehber
Bulut ortamlarında çalışıyorsanız, bir gün mutlaka “bu sunucunun tam kopyasını almam lazım” diyeceksiniz. İster yeni bir instance açmak için, ister disaster recovery planı kurmak için, ister test ortamı hazırlamak için olsun, AWS’de bu ihtiyacın cevabı AMI’dır (Amazon Machine Image). Ama AMI sadece “snapshot al ve unut” değil, doğru yönetilmediğinde hem maliyeti hem de operasyonel karmaşıklığı artıran bir yapıdır. Bu yazıda AMI oluşturmaktan başlayarak, otomatikleştirmeye, maliyeti düşürmeye ve production’da gerçekten işe yarayan pratiklere kadar her şeyi ele alacağız.
AMI Nedir ve Nasıl Çalışır
AMI, bir EC2 instance’ını başlatmak için gereken tüm bilgileri içeren bir şablondur. İçinde şunlar bulunur:
- Root volume snapshot’ı: İşletim sistemi ve kurulu yazılımlar
- Launch permissions: Hangi hesapların bu AMI’yı kullanabileceği
- Block device mapping: Instance başladığında hangi volume’lerin bağlanacağı bilgisi
AMI’lar bölgeye özgüdür. us-east-1’de oluşturduğunuz bir AMI’yı eu-west-1’de kullanmak istiyorsanız kopyalamanız gerekir. Bu basit ama sık unutulan bir detay.
AMI’ların iki tipi vardır:
- EBS-backed AMI: Root volume EBS’te tutulur, instance durdurulabilir ve başlatılabilir. Production’da neredeyse her zaman bu.
- Instance store-backed AMI: Root volume instance store’da tutulur, instance durdurulunca veriler gider. Artık pek kullanılmıyor.
İlk AMI’nızı Oluşturmak
AWS Console Üzerinden
En basit yol Console üzerinden gitmek. EC2 > Instances altında instance’ınızı seçin, sağ tıklayıp “Image and templates > Create image” deyin. Ama bu yolu production’da manuel olarak yapmak istemezsiniz, asıl güç AWS CLI ve otomasyon araçlarında.
AWS CLI ile AMI Oluşturma
# Temel AMI oluşturma
aws ec2 create-image
--instance-id i-0123456789abcdef0
--name "webserver-prod-$(date +%Y%m%d-%H%M%S)"
--description "Production web server - weekly backup"
--no-reboot
--region us-east-1
# Çıktı olarak AMI ID gelir:
# { "ImageId": "ami-0123456789abcdef0" }
Burada kritik bir parametre var: --no-reboot. Bu parametre verildiğinde AWS, AMI oluştururken instance’ı yeniden başlatmaz. Peki bu ne anlama gelir? Dosya sistemi tutarlılığı açısından risk taşır. Eğer uygulamanız veritabanı yazıyor, loglar buffer’da bekliyorsa snapshot tutarsız olabilir. Production instance’larında --no-reboot kullanmak istiyorsanız önce uygulamanızı graceful olarak durdurmalısınız.
Reboot İzni Vererek AMI Oluşturma
# Instance'ı yeniden başlatarak (daha güvenli, tutarlı snapshot)
aws ec2 create-image
--instance-id i-0123456789abcdef0
--name "appserver-$(date +%Y%m%d)"
--description "Application server AMI with reboot"
--region us-east-1
# --no-reboot yazmıyoruz, default davranış reboot'tur
AMI oluşturma işlemi hemen tamamlanmaz. Snapshot’ların alınması zaman alır. AMI durumunu kontrol etmek için:
# AMI durumunu kontrol et
aws ec2 describe-images
--image-ids ami-0123456789abcdef0
--query 'Images[0].State'
--output text
# Tüm kendi AMI'larınızı listele
aws ec2 describe-images
--owners self
--query 'Images[*].[ImageId,Name,CreationDate,State]'
--output table
--region us-east-1
Etiketleme Stratejisi: Kaosa Giden Yol veya Düzene Giden Yol
AMI’larda etiketleme, iki ay sonra “bu AMI’yı neden aldım, silebilir miyim” diye sormamak için kritik. Şu etiketi mutlaka koyun:
# AMI oluştururken etiket ekle
aws ec2 create-image
--instance-id i-0123456789abcdef0
--name "api-server-v2.3.1-$(date +%Y%m%d)"
--tag-specifications
'ResourceType=image,Tags=[
{Key=Environment,Value=production},
{Key=Application,Value=api-server},
{Key=Version,Value=2.3.1},
{Key=CreatedBy,Value=jenkins-pipeline},
{Key=RetentionDays,Value=30}
]'
--region us-east-1
# Mevcut AMI'ya etiket ekle
aws ec2 create-tags
--resources ami-0123456789abcdef0
--tags
Key=Environment,Value=production
Key=Application,Value=api-server
Key=BackupType,Value=weekly
RetentionDays etiketi özellikle önemli. Temizlik scriptlerinizde bu etiketi okuyarak otomatik silme yapabilirsiniz. Bunu ilerleyen bölümlerde göreceğiz.
AMI Oluşturmayı Otomatikleştirme
Bash Script ile Haftalık AMI Backup
Gerçek dünyada AMI oluşturmayı cron job veya pipeline’a bağlarsınız. İşte production’da kullandığım bir script:
#!/bin/bash
# ami-backup.sh - Production instance AMI backup scripti
set -euo pipefail
# Konfigürasyon
REGION="us-east-1"
RETENTION_DAYS=14
DATE=$(date +%Y%m%d-%H%M%S)
LOG_FILE="/var/log/ami-backup.log"
# Loglamak için fonksiyon
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Backup alınacak instance'ları tag üzerinden bul
# "Backup=true" etiketi olan instance'lar
INSTANCES=$(aws ec2 describe-instances
--region "$REGION"
--filters "Name=tag:Backup,Values=true"
"Name=instance-state-name,Values=running,stopped"
--query 'Reservations[*].Instances[*].[InstanceId,Tags[?Key==`Name`].Value|[0]]'
--output text)
if [ -z "$INSTANCES" ]; then
log "WARN: Backup alınacak instance bulunamadı"
exit 0
fi
# Her instance için AMI oluştur
while IFS=$'t' read -r instance_id instance_name; do
log "INFO: Backup başlıyor - Instance: $instance_id ($instance_name)"
AMI_NAME="${instance_name:-unknown}-backup-${DATE}"
AMI_ID=$(aws ec2 create-image
--region "$REGION"
--instance-id "$instance_id"
--name "$AMI_NAME"
--no-reboot
--tag-specifications
"ResourceType=image,Tags=[
{Key=Name,Value=${AMI_NAME}},
{Key=SourceInstance,Value=${instance_id}},
{Key=CreatedDate,Value=${DATE}},
{Key=RetentionDays,Value=${RETENTION_DAYS}},
{Key=BackupType,Value=automated}
]"
--query 'ImageId'
--output text)
log "INFO: AMI oluşturuldu - $AMI_ID ($AMI_NAME)"
# AMI'ya bağlı snapshot'ları da etiketle
aws ec2 describe-images
--region "$REGION"
--image-ids "$AMI_ID"
--query 'Images[0].BlockDeviceMappings[*].Ebs.SnapshotId'
--output text | tr 't' 'n' | while read -r snap_id; do
if [ -n "$snap_id" ] && [ "$snap_id" != "None" ]; then
aws ec2 create-tags
--region "$REGION"
--resources "$snap_id"
--tags
Key=AMIId,Value="$AMI_ID"
Key=SourceInstance,Value="$instance_id"
Key=RetentionDays,Value="$RETENTION_DAYS"
log "INFO: Snapshot etiketlendi - $snap_id"
fi
done
done <<< "$INSTANCES"
log "INFO: Backup işlemi tamamlandı"
Bu script’i crontab’a ekleyebilirsiniz:
# Crontab - Her Pazar gece 02:00'de çalıştır
0 2 * * 0 /opt/scripts/ami-backup.sh >> /var/log/ami-backup.log 2>&1
Eski AMI’ları Temizleme
AMI oluşturmak ücretsiz değil. Her AMI’nın altında EBS snapshot’ları yatar ve bu snapshot’lar GB başına ücretlendirilir. Retention politikası olmadan bakım yapmayan ekiplerin hesaplarında yüzlerce gereksiz AMI biriktiğini gördüm. İşte temizlik scripti:
#!/bin/bash
# ami-cleanup.sh - Eski AMI'ları temizle
REGION="us-east-1"
DATE_FORMAT="%Y-%m-%dT%H:%M:%S"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# RetentionDays etiketine sahip AMI'ları bul ve süresi dolmuşları sil
aws ec2 describe-images
--region "$REGION"
--owners self
--filters "Name=tag:RetentionDays,Values=*"
--query 'Images[*].[ImageId,CreationDate,Tags[?Key==`RetentionDays`].Value|[0],Name]'
--output text | while IFS=$'t' read -r ami_id creation_date retention_days ami_name; do
# Oluşturma tarihinden bu yana kaç gün geçti
creation_ts=$(date -d "$creation_date" +%s 2>/dev/null ||
date -j -f "%Y-%m-%dT%H:%M:%S+00:00" "$creation_date" +%s)
current_ts=$(date +%s)
age_days=$(( (current_ts - creation_ts) / 86400 ))
if [ "$age_days" -gt "$retention_days" ]; then
log "INFO: AMI siliniyor - $ami_id ($ami_name) - ${age_days} gün eski, limit: ${retention_days} gün"
# Önce snapshot ID'lerini topla
SNAPSHOT_IDS=$(aws ec2 describe-images
--region "$REGION"
--image-ids "$ami_id"
--query 'Images[0].BlockDeviceMappings[*].Ebs.SnapshotId'
--output text)
# AMI'yı deregister et
aws ec2 deregister-image
--region "$REGION"
--image-id "$ami_id"
# Snapshot'ları sil
for snap_id in $SNAPSHOT_IDS; do
if [ -n "$snap_id" ] && [ "$snap_id" != "None" ]; then
log "INFO: Snapshot siliniyor - $snap_id"
aws ec2 delete-snapshot
--region "$REGION"
--snapshot-id "$snap_id"
fi
done
else
log "DEBUG: AMI korunuyor - $ami_id - ${age_days}/${retention_days} gün"
fi
done
Önemli not: AMI deregister etmek ile silmek aynı şey değil gibi görünse de, deregister-image komutu AMI’yı kullanılamaz hale getirir ama altındaki snapshot’ları silmez. Snapshot’ları ayrıca silmeniz gerekir. Bu adımı atlamak maliyet tasarrufu yapıyorum zannederken yapmamak anlamına gelir.
AMI’ları Farklı Bölgelere Kopyalama
Disaster recovery için AMI’larınızı farklı region’lara kopyalamanız gerekebilir:
# AMI'yı eu-west-1'e kopyala
aws ec2 copy-image
--source-region us-east-1
--source-image-id ami-0123456789abcdef0
--region eu-west-1
--name "webserver-prod-dr-copy-$(date +%Y%m%d)"
--description "DR copy from us-east-1"
--encrypted
--kms-key-id alias/aws/ebs
# Kopyalama tamamlanana kadar bekle
aws ec2 wait image-available
--region eu-west-1
--image-ids ami-0987654321fedcba0
echo "AMI kopyalama tamamlandı"
--encrypted bayrağını kullanarak DR kopyalarınızı şifreli tutmanızı öneririm. Production data içeren snapshot’ları şifresiz bırakmak güvenlik açığı yaratır.
AMI’dan Instance Başlatma
AMI oluşturdunuz, şimdi bundan instance açacaksınız:
# Basit instance başlatma
aws ec2 run-instances
--image-id ami-0123456789abcdef0
--instance-type t3.medium
--key-name my-keypair
--security-group-ids sg-0123456789abcdef0
--subnet-id subnet-0123456789abcdef0
--count 1
--tag-specifications
'ResourceType=instance,Tags=[
{Key=Name,Value=webserver-from-ami},
{Key=Environment,Value=staging}
]'
--user-data file://startup-script.sh
--region us-east-1
# Instance hazır olana kadar bekle
aws ec2 wait instance-running
--instance-ids i-0123456789abcdef0
--region us-east-1
AWS Data Lifecycle Manager ile AMI Otomasyonu
Manuel script yazmak yerine AWS’nin kendi servisi olan Data Lifecycle Manager (DLM) kullanabilirsiniz. Bu servis, belirli etiketlere sahip instance’lardan otomatik olarak AMI alır ve retention politikası uygular.
# DLM lifecycle policy oluştur
aws dlm create-lifecycle-policy
--description "Weekly AMI backup for production servers"
--state ENABLED
--execution-role-arn arn:aws:iam::123456789012:role/AWSDataLifecycleManagerDefaultRole
--policy-details '{
"PolicyType": "IMAGE_MANAGEMENT",
"ResourceTypes": ["INSTANCE"],
"TargetTags": [
{"Key": "Backup", "Value": "true"}
],
"Schedules": [
{
"Name": "Weekly-Sunday-Backup",
"CreateRule": {
"Interval": 1,
"IntervalUnit": "WEEKS",
"Times": ["02:00"]
},
"RetainRule": {
"Count": 4
},
"TagsToAdd": [
{"Key": "CreatedByDLM", "Value": "true"},
{"Key": "BackupSchedule", "Value": "weekly"}
],
"CopyTags": true,
"ShareRules": []
}
],
"Parameters": {
"NoReboot": false
}
}'
--region us-east-1
DLM’in avantajı yönetim overhead’inin az olması. Dezavantajı ise özel senaryolarda esneklik sunmaması. Örneğin deployment öncesi ve sonrası AMI almak istiyorsanız DLM yetersiz kalır, kendi scriptinizi yazarsınız.
Golden AMI Pattern: Kurumsal Kullanım
Büyük ortamlarda her ekibin kendi AMI’sını bakımı yerine “Golden AMI” yaklaşımı benimsenir. Bunu şöyle düşünün: Güvenlik yamalarını, monitoring agent’ını, şirket sertifikalarını içeren bir base AMI hazırlarsınız. Tüm uygulama AMI’ları bu base AMI üzerinden türetilir.
Packer ile bu süreci otomatikleştirebilirsiniz:
# packer-golden-ami.pkr.hcl
# Bu dosyayı packer build ile çalıştırın
# Önce Packer'ın kurulu olduğundan emin olun
packer --version
# Template validate et
packer validate packer-golden-ami.pkr.hcl
# Build başlat
packer build
-var "aws_region=us-east-1"
-var "base_ami=ami-0c02fb55956c7d316"
-var "version=$(date +%Y%m%d)"
packer-golden-ami.pkr.hcl
Packer build sonunda yeni bir AMI ID üretir. Bu ID’yi SSM Parameter Store’a yazabilirsiniz:
# Golden AMI ID'yi SSM'e yaz
# Tüm ekipler buradan okur, AMI ID hardcode etmez
aws ssm put-parameter
--name "/golden-ami/amazon-linux2/latest"
--value "ami-0newgoldenami123456"
--type "String"
--overwrite
--region us-east-1
# Uygulama deployment'larında AMI ID'yi SSM'den oku
GOLDEN_AMI=$(aws ssm get-parameter
--name "/golden-ami/amazon-linux2/latest"
--query 'Parameter.Value'
--output text
--region us-east-1)
echo "Kullanılacak Golden AMI: $GOLDEN_AMI"
Bu pattern’in güzelliği şu: Bir güvenlik açığı çıktığında Golden AMI’yı güncelleyip SSM’deki değeri değiştirirsiniz. Bir sonraki deployment’ta tüm sistemler otomatik olarak güncellenmiş AMI’yı kullanır.
AMI Paylaşımı
Aynı organization içindeki farklı AWS hesapları arasında AMI paylaşabilirsiniz:
# AMI'yı başka bir hesapla paylaş
aws ec2 modify-image-attribute
--image-id ami-0123456789abcdef0
--launch-permission "Add=[{UserId=987654321098}]"
--region us-east-1
# Public paylaşım (dikkatli olun!)
aws ec2 modify-image-attribute
--image-id ami-0123456789abcdef0
--launch-permission "Add=[{Group=all}]"
--region us-east-1
# AMI paylaşım durumunu kontrol et
aws ec2 describe-image-attribute
--image-id ami-0123456789abcdef0
--attribute launchPermission
--region us-east-1
# Paylaşımı kaldır
aws ec2 modify-image-attribute
--image-id ami-0123456789abcdef0
--launch-permission "Remove=[{UserId=987654321098}]"
--region us-east-1
Public paylaşımda dikkatli olun. İçinde credential, SSH key veya özel konfigürasyon olan AMI’ları asla public yapmayın. Pek çok güvenlik olayı bu şekilde gereksiz yere public yapılan AMI’lardan çıkmıştır.
Maliyet Optimizasyonu
AMI yönetiminde maliyet optimizasyonu için bazı pratik öneriler:
- Kullanılmayan AMI’ları düzenli temizleyin: Yukarıdaki cleanup script’ini 2 haftada bir çalıştırın
- Snapshot deduplication’dan yararlanın: AWS, aynı veriyi içeren snapshot bloklarını otomatik olarak tekrar kullanır. Bu yüzden incremental backup’lar ilkinden çok daha ucuzdur
- AMI’ları sıkıştırın: Instance üzerindeki kullanılmayan dosyaları, geçici verileri ve log’ları temizledikten sonra AMI alın. Küçük snapshot = daha az maliyet
- Infrequent Access tier kullanın: Nadir kullanılan snapshot’ları EBS Snapshot Archive’e taşıyın, maliyeti yüzde 75 düşer
- Region seçimine dikkat edin: AMI snapshot’ları us-east-1’de daha ucuzdur, DR kopyalarını tutacaksanız bunu hesaba katın
Sorun Giderme
AMI “pending” durumunda takılıyor: Genellikle büyük volume’lerde normaldir. 200 GB disk için 30-40 dakika beklenmesi normal. Ama 2 saat geçmişse AWS Support’a açın.
AMI’dan başlatılan instance ayağa kalkmıyor: Instance System Log’larını kontrol edin. Genellikle /etc/fstab içinde olmayan bir volume mount noktası veya corrupted snapshot kaynaklıdır.
Cross-region copy başarısız oluyor: KMS key izinleri en sık karşılaşılan sorun. Source region’daki key politikasının hedef region’a izin verdiğinden emin olun.
AMI deregister edilmiş ama snapshot’lar hala orada: Normal bir durum. Yukarıdaki cleanup script’i gibi snapshot’ları ayrıca silmeniz gerekiyor.
Sonuç
AMI yönetimi ilk bakışta basit görünür: al, sakla, kullan. Ama production ortamında bu işin etiketleme stratejisi, otomatik temizlik, cross-region replikasyon, maliyet takibi ve güvenlik boyutları vardır. Yazı boyunca anlattıklarımı özetlemek gerekirse:
- Etiketleme yapın: RetentionDays, Environment, Application etiketleri olmadan AMI yönetimi kaosa döner
- Temizliği otomatikleştirin: Manuel silmeye güvenmeyin, script veya DLM kullanın
- Snapshot’ları unutmayın: AMI deregister etmek snapshot’ları silmez
- Golden AMI pattern: Büyük ortamlarda base AMI yaklaşımı operasyonel yükü ciddi azaltır
- SSM Parameter Store: AMI ID’leri hardcode yerine SSM’den okuyun
- Güvenli paylaşım: AMI paylaşırken credential ve key olmadığından emin olun
Bu pratikleri uyguladıktan sonra AMI yönetimi artık “zaman zaman aklıma gelen bir sorun” değil, sistematik ve otomatik bir süreç haline gelir. Ekibiniz sabah kalktığında backup’ların alınıp alınmadığını sorgulamak zorunda kalmaz.
