AWS Fargate ile Sunucusuz Konteyner Yönetimi

Konteyner teknolojileri hayatımıza girdiğinde, “artık her şey daha kolay” diye düşünmüştük. Sonra EC2 üzerinde cluster yönetmeye başladık, node patching derdi, capacity planning baş ağrısı, güvenlik güncellemeleri… Derken AWS Fargate sahneye çıktı ve “sunucu yönetmeyin, sadece konteyneri çalıştırın” dedi. Bu yazıda Fargate’i gerçek dünya senaryolarıyla ele alacağız; ne zaman kullanmalı, nasıl yapılandırmalı ve production’da nelere dikkat etmeli bunları konuşacağız.

AWS Fargate Nedir ve Neden Önemlidir

Fargate, temelde bir serverless compute engine’dir. ECS (Elastic Container Service) veya EKS (Elastic Kubernetes Service) ile birlikte çalışır ve sizin için şunu yapar: VM’leri provizyon etmez, cluster kapasitesini yönetmez, işletim sistemi patch’lerini takip etmez. Siz sadece CPU ve memory tanımlarsınız, container image’ı belirtirsiniz ve Fargate gerisini halleder.

Klasik EC2 tabanlı ECS kullanırken şöyle bir döngü yaşarsınız: Instance tipi seçersiniz, Auto Scaling Group kurarsınız, cluster’da boş kapasite olup olmadığını takip edersiniz, büyük bir deployment sırasında “insufficient capacity” hatasıyla karşılaşırsınız ve saatlerce uğraşırsınız. Fargate bu döngüyü keser.

Ama şunu da söyleyelim: Fargate her senaryo için mükemmel değil. Uzun süreli, yüksek CPU’lu iş yükleri için maliyetli olabilir. GPU gerektiren workload’lar için uygun değil. Özel kernel parametrelerine ihtiyaç duyan uygulamalar için de tercih edilmez. Bunları bilerek devam edelim.

Temel Kavramlar

Fargate dünyasına girmeden önce birkaç kavramı netleştirmek gerekiyor.

Task Definition: Konteynerin nasıl çalışacağını tanımlayan JSON belgesi. Image, CPU, memory, environment variable’lar, port mapping’ler ve IAM rolleri burada belirlenir.

Task: Task Definition’ın bir instance’ı. Bir veya birden fazla konteyner içerebilir.

Service: Belirli sayıda Task’ın sürekli çalışmasını sağlayan ECS bileşeni. Bir Task ölürse Service onu yeniden başlatır.

Cluster: Task ve Service’lerin çalıştığı mantıksal gruplama birimi. Fargate’de cluster’a bağlı EC2 instance’ı olmaz.

Task Execution Role: Fargate’in ECR’dan image çekmesi, CloudWatch’a log yazması gibi işlemler için kullandığı IAM rolü.

Task Role: Uygulama kodunun AWS servislerine (S3, DynamoDB, vs.) erişmek için kullandığı IAM rolü.

İlk Fargate Cluster’ını Kurmak

AWS CLI ile başlayalım. Önce bir cluster oluşturalım:

aws ecs create-cluster 
  --cluster-name production-cluster 
  --capacity-providers FARGATE FARGATE_SPOT 
  --default-capacity-provider-strategy 
    capacityProvider=FARGATE,weight=1,base=1 
    capacityProvider=FARGATE_SPOT,weight=4 
  --region eu-west-1

Burada dikkat edin: FARGATE_SPOT kullanıyoruz. Normal Fargate fiyatının yaklaşık %70 daha ucuzu. Interrupt toleranslı workload’lar için (batch işleri, non-kritik servisler) harika bir seçenek. Base değerini 1 yaparak en az bir Task’ın normal Fargate’de çalışmasını garantiliyoruz, geri kalanlar Spot üzerinde.

Task Definition Oluşturmak

Gerçek bir web uygulaması için Task Definition yazalım. Diyelim ki bir Node.js API servisimiz var:

cat > task-definition.json << 'EOF'
{
  "family": "nodejs-api",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/nodejs-api-task-role",
  "containerDefinitions": [
    {
      "name": "nodejs-api",
      "image": "123456789012.dkr.ecr.eu-west-1.amazonaws.com/nodejs-api:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        },
        {
          "name": "PORT",
          "value": "3000"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:eu-west-1:123456789012:secret:prod/nodejs-api/db-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/nodejs-api",
          "awslogs-region": "eu-west-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      },
      "essential": true
    }
  ]
}
EOF

aws ecs register-task-definition 
  --cli-input-json file://task-definition.json 
  --region eu-west-1

Burada önemli noktalara değinelim:

  • secrets bloğu: Şifreleri environment variable olarak düz metin yazmak yerine Secrets Manager’dan çekiyoruz. Bu kritik bir güvenlik pratiği.
  • healthCheck: Uygulamanın gerçekten sağlıklı çalışıp çalışmadığını test ediyor. startPeriod değerini uygulamanızın boot süresine göre ayarlayın.
  • networkMode awsvpc: Fargate için zorunlu. Her Task kendi ENI’sini alır.

IAM Rollerini Doğru Yapılandırmak

Bu kısım en çok hata yapılan yer. İki farklı rolü karıştırmayın:

# Task Execution Role - Fargate'in kendisi kullanır
aws iam create-role 
  --role-name ecsTaskExecutionRole 
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": {"Service": "ecs-tasks.amazonaws.com"},
      "Action": "sts:AssumeRole"
    }]
  }'

# AWS managed policy'yi ekle
aws iam attach-role-policy 
  --role-name ecsTaskExecutionRole 
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

# Secrets Manager erişimi için ek policy
aws iam put-role-policy 
  --role-name ecsTaskExecutionRole 
  --policy-name SecretsManagerAccess 
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "kms:Decrypt"
      ],
      "Resource": [
        "arn:aws:secretsmanager:eu-west-1:123456789012:secret:prod/*"
      ]
    }]
  }'

Task Role ise uygulamanızın ihtiyaç duyduğu servislere göre yapılandırılır. Minimum yetki prensibini uygulayın:

# Uygulama sadece S3 okuma ve DynamoDB yazma yapıyorsa
aws iam put-role-policy 
  --role-name nodejs-api-task-role 
  --policy-name AppPermissions 
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": ["s3:GetObject"],
        "Resource": "arn:aws:s3:::my-app-bucket/*"
      },
      {
        "Effect": "Allow",
        "Action": [
          "dynamodb:PutItem",
          "dynamodb:GetItem",
          "dynamodb:UpdateItem"
        ],
        "Resource": "arn:aws:dynamodb:eu-west-1:123456789012:table/my-table"
      }
    ]
  }'

ECS Service Oluşturmak ve Load Balancer Entegrasyonu

Production’da bir ALB (Application Load Balancer) arkasında çalışacak bir Service kuralım:

aws ecs create-service 
  --cluster production-cluster 
  --service-name nodejs-api-service 
  --task-definition nodejs-api:1 
  --desired-count 3 
  --launch-type FARGATE 
  --network-configuration "awsvpcConfiguration={
    subnets=[subnet-abc123,subnet-def456,subnet-ghi789],
    securityGroups=[sg-xyz789],
    assignPublicIp=DISABLED
  }" 
  --load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:eu-west-1:123456789012:targetgroup/nodejs-api/abc123,containerName=nodejs-api,containerPort=3000" 
  --deployment-configuration "maximumPercent=200,minimumHealthyPercent=100" 
  --capacity-provider-strategy 
    capacityProvider=FARGATE,weight=1,base=1 
    capacityProvider=FARGATE_SPOT,weight=4 
  --region eu-west-1

Dikkat edilmesi gereken noktalar:

  • assignPublicIp=DISABLED: Private subnet’te çalışıyoruz. NAT Gateway üzerinden internete çıkış yapılır. Public IP vermek genellikle kötü bir pratik.
  • minimumHealthyPercent=100: Deployment sırasında mevcut kapasiteyi düşürmüyoruz.
  • maximumPercent=200: Deployment sırasında mevcut kapasiteyi iki katına çıkarabiliyoruz (blue/green benzeri davranış).

Auto Scaling Yapılandırması

Trafik dalgalanmalarına karşı Auto Scaling kurmak Fargate’de oldukça kolay:

# Service'i scalable target olarak kaydet
aws application-autoscaling register-scalable-target 
  --service-namespace ecs 
  --scalable-dimension ecs:service:DesiredCount 
  --resource-id service/production-cluster/nodejs-api-service 
  --min-capacity 2 
  --max-capacity 20

# CPU kullanımına göre ölçeklendirme
aws application-autoscaling put-scaling-policy 
  --policy-name nodejs-api-cpu-scaling 
  --service-namespace ecs 
  --scalable-dimension ecs:service:DesiredCount 
  --resource-id service/production-cluster/nodejs-api-service 
  --policy-type TargetTrackingScaling 
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 60.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
    },
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }'

# Memory kullanımına göre ölçeklendirme
aws application-autoscaling put-scaling-policy 
  --policy-name nodejs-api-memory-scaling 
  --service-namespace ecs 
  --scalable-dimension ecs:service:DesiredCount 
  --resource-id service/production-cluster/nodejs-api-service 
  --policy-type TargetTrackingScaling 
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 70.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ECSServiceAverageMemoryUtilization"
    },
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }'

ScaleOutCooldown’u 60 saniye, ScaleInCooldown’u 300 saniye yapıyoruz. Hızlı büyüyüp yavaş küçülmek, ani trafik artışlarında kötü kullanıcı deneyimini önler.

Scheduled Tasks ile Batch İşleri

Fargate’in güçlü kullanım alanlarından biri de zamanlanmış batch işleri. Örneğin her gece çalışan bir raporlama işi:

# EventBridge rule oluştur
aws events put-rule 
  --name nightly-report-job 
  --schedule-expression "cron(0 2 * * ? *)" 
  --state ENABLED 
  --region eu-west-1

# ECS Task'ı hedef olarak ekle
aws events put-targets 
  --rule nightly-report-job 
  --targets '[
    {
      "Id": "nightly-report-target",
      "Arn": "arn:aws:ecs:eu-west-1:123456789012:cluster/production-cluster",
      "RoleArn": "arn:aws:iam::123456789012:role/events-ecs-role",
      "EcsParameters": {
        "TaskDefinitionArn": "arn:aws:ecs:eu-west-1:123456789012:task-definition/report-generator:5",
        "TaskCount": 1,
        "LaunchType": "FARGATE",
        "NetworkConfiguration": {
          "awsvpcConfiguration": {
            "Subnets": ["subnet-abc123"],
            "SecurityGroups": ["sg-batch-jobs"],
            "AssignPublicIp": "DISABLED"
          }
        },
        "PlatformVersion": "LATEST"
      }
    }
  ]'

Bu yaklaşım özellikle cron job’ları için harika. EC2 üzerinde cron çalıştırmak yerine her iş için tam ihtiyacı kadar kaynak ayıran bir Task başlatıyorsunuz ve iş bitince Task durduruluyor. Para ödemiyorsunuz.

Fargate Spot ile Maliyet Optimizasyonu

Production ortamında maliyet optimizasyonu için bir senaryo düşünelim. Bir e-ticaret sitesinde sipariş işleme servisi var. Bu servis interrupt toleranslı değil ama image processing servisi interrupt toleranslı.

# Image processing servisi - interrupt toleranslı, Spot kullan
aws ecs create-service 
  --cluster production-cluster 
  --service-name image-processor 
  --task-definition image-processor:3 
  --desired-count 5 
  --capacity-provider-strategy 
    capacityProvider=FARGATE_SPOT,weight=1,base=0 
  --network-configuration "awsvpcConfiguration={
    subnets=[subnet-abc123,subnet-def456],
    securityGroups=[sg-processors],
    assignPublicIp=DISABLED
  }" 
  --region eu-west-1

Fargate Spot’ta Task interrupt edildiğinde 2 dakika önceden SIGTERM sinyali gelir. Uygulamanızın bu sinyali düzgün yakalaması gerekir. Node.js için basit bir örnek:

# Dockerfile'da graceful shutdown için
# Uygulama kodunuzda şunu yapın:
cat > graceful-shutdown.js << 'EOF'
process.on('SIGTERM', async () => {
  console.log('SIGTERM received, starting graceful shutdown...');
  
  // Yeni istekleri almayı durdur
  server.close(() => {
    console.log('HTTP server closed');
  });
  
  // Devam eden işleri tamamla (max 90 saniye)
  await finishInProgressJobs();
  
  // DB bağlantılarını kapat
  await db.close();
  
  console.log('Graceful shutdown complete');
  process.exit(0);
});
EOF

CloudWatch ile İzleme ve Alerting

Fargate Task’larınızı izlemek için CloudWatch Insights kullanın:

# Son 1 saatte hata veren Task'ları bul
aws logs start-query 
  --log-group-name /ecs/nodejs-api 
  --start-time $(date -d '1 hour ago' +%s) 
  --end-time $(date +%s) 
  --query-string 'fields @timestamp, @message
    | filter @message like /ERROR/
    | stats count() as error_count by bin(5m)
    | sort @timestamp desc'

# Alarm oluştur - Task sayısı 0'a düşerse bildir
aws cloudwatch put-metric-alarm 
  --alarm-name "fargate-nodejs-api-no-tasks" 
  --alarm-description "NodeJS API servisinde çalışan Task kalmadı" 
  --metric-name RunningTaskCount 
  --namespace AWS/ECS 
  --statistic Average 
  --period 60 
  --threshold 1 
  --comparison-operator LessThanThreshold 
  --evaluation-periods 2 
  --dimensions Name=ClusterName,Value=production-cluster Name=ServiceName,Value=nodejs-api-service 
  --alarm-actions arn:aws:sns:eu-west-1:123456789012:ops-alerts 
  --treat-missing-data breaching

Deployment Stratejileri

Fargate ile sıfır kesinti deployment için birkaç yaklaşım var.

Rolling update en basiti ve çoğu zaman yeterli. Bunu zaten Service kurulumunda yapılandırdık. Ama daha gelişmiş senaryolar için CodeDeploy ile Blue/Green deployment da yapılabilir.

Yeni bir Task Definition revision deployment’ı şöyle yapılır:

# Yeni image ile Task Definition'ı güncelle
NEW_IMAGE="123456789012.dkr.ecr.eu-west-1.amazonaws.com/nodejs-api:v2.1.0"

# Mevcut task definition'ı al ve güncelle
aws ecs describe-task-definition 
  --task-definition nodejs-api 
  --query 'taskDefinition' 
  | jq --arg IMAGE "$NEW_IMAGE" 
    '.containerDefinitions[0].image = $IMAGE | 
     del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' 
  > updated-task-definition.json

# Yeni revision'ı kaydet
NEW_TASK_DEF_ARN=$(aws ecs register-task-definition 
  --cli-input-json file://updated-task-definition.json 
  --query 'taskDefinition.taskDefinitionArn' 
  --output text)

echo "Yeni Task Definition: $NEW_TASK_DEF_ARN"

# Service'i güncelle
aws ecs update-service 
  --cluster production-cluster 
  --service nodejs-api-service 
  --task-definition $NEW_TASK_DEF_ARN 
  --region eu-west-1

# Deployment'ı izle
aws ecs wait services-stable 
  --cluster production-cluster 
  --services nodejs-api-service 
  --region eu-west-1

echo "Deployment tamamlandı!"

Güvenlik Pratikleri

Fargate’de güvenlik için birkaç kritik nokta:

Container Insights aktif etmek: Hem metrics hem de container seviyesi görünürlük sağlar.

aws ecs update-cluster-settings 
  --cluster production-cluster 
  --settings name=containerInsights,value=enabled

Read-only root filesystem: Konteynerin dosya sistemine yazma izni vermemek, potansiyel saldırı yüzeyini azaltır. Task Definition’da şunu ekleyin:

# Task definition containerDefinitions içine eklenecek
# "readonlyRootFilesystem": true,
# "tmpfs": [{"containerPath": "/tmp", "size": 512}]

aws ecs register-task-definition 
  --family nodejs-api-secure 
  --cli-input-json '{
    "family": "nodejs-api-secure",
    "networkMode": "awsvpc",
    "requiresCompatibilities": ["FARGATE"],
    "cpu": "512",
    "memory": "1024",
    "containerDefinitions": [{
      "name": "nodejs-api",
      "image": "123456789012.dkr.ecr.eu-west-1.amazonaws.com/nodejs-api:latest",
      "readonlyRootFilesystem": true,
      "linuxParameters": {
        "tmpfs": [{"containerPath": "/tmp", "size": 512}]
      },
      "privileged": false,
      "user": "1000:1000"
    }]
  }'

VPC Endpoint kullanımı: Fargate Task’larınızın ECR, S3 ve diğer AWS servislerine erişimi için internet yerine VPC Endpoint kullanın. Bu hem güvenlik hem de maliyet açısından avantajlı.

Gerekli VPC Endpoint’ler:

  • com.amazonaws.eu-west-1.ecr.api: ECR API erişimi
  • com.amazonaws.eu-west-1.ecr.dkr: Docker image pull
  • com.amazonaws.eu-west-1.s3: ECR layer’ları S3’te tutulur
  • com.amazonaws.eu-west-1.logs: CloudWatch Logs
  • com.amazonaws.eu-west-1.secretsmanager: Secrets Manager

Yaygın Sorunlar ve Çözümleri

Production’da sık karşılaşılan sorunları listeleyelim:

Task “PENDING” durumunda takılı kalıyor: Genellikle ENI oluşturma problemidir. Subnet’in IP havuzunun dolup dolmadığını kontrol edin. /24 bir subnet sadece 251 kullanılabilir IP verir ve her Fargate Task bir IP tüketir.

EssentialContainerExited hatası: Sidecar konteynerlerinizden biri ölüyordur. CloudWatch Logs’ta o konteynerin exit code’unu kontrol edin.

Image pull hatası: ECR authentication sorunu veya VPC Endpoint eksikliği. Task Execution Role’ünün ECR yetkilerini ve VPC Endpoint yapılandırmasını kontrol edin.

Yavaş scale-out: Fargate’de yeni Task başlatmak 30-90 saniye sürebilir. Önceden ölçeklendirme (scheduled scaling) veya daha agresif scale-out politikası gerekebilir.

Out of Memory hatası: Task tanımındaki memory değerini artırın ama önce CloudWatch Insights’ta gerçek kullanımı inceleyin. Çoğu zaman memory leak vardır.

Maliyet Yönetimi

Fargate maliyeti hesaplamak için şunu bilin:

  • vCPU başına saatlik ücret
  • GB memory başına saatlik ücret
  • Minimum 1 dakika, sonra saniye bazlı ücretlendirme

Maliyeti optimize etmek için:

  • Fargate Spot kullanın interrupt toleranslı workload’lar için
  • CPU ve memory’yi gereğinden büyük tanımlamayın; CloudWatch Insights ile gerçek kullanımı ölçün
  • Gerektiğinde scale-in agresif olun
  • Geliştirme ortamlarında Task’ları çalışma saatleri dışında sıfıra düşürün

Sonuç

AWS Fargate, özellikle küçük ve orta ölçekli ekipler için büyük bir operasyonel yük azaltır. Cluster node’larını yönetmek, instance tip seçmek, kernel güncellemelerini takip etmek yerine sadece uygulamanıza odaklanırsınız. Bu “operasyonel sürtünmenin” azalması, deployment sıklığını ve genel verimliliği artırır.

Ancak Fargate’i körü körüne her yere uygulamayın. Uzun süreli hesaplama işleri, GPU gerektiren workload’lar, çok düşük latency gerektiren ve her milisaniyenin kritik olduğu senaryolar için EC2 tabanlı çözümler hala geçerli. Hibrit bir yaklaşım, yani stateful ve latency-sensitive servisleri EC2’de, stateless ve batch workload’ları Fargate’de çalıştırmak çoğu zaman en mantıklı seçimdir.

Son olarak: Fargate’e geçmeden önce mevcut infrastructure’ınızı iyi belgeleyin, network yapınızı (VPC, subnet, security group) dikkatlice planlayın ve her şeyden önce IAM rollerini doğru yapılandırın. Bu üç şeyi doğru yaparsanız gerisini kolayca öğrenirsiniz.

Bir yanıt yazın

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