Skip to content
~/sph.sh

AWS Fargate 104: CDK, Terraform ve SAM ile Deploy

Fargate'i farklı IaC araçlarıyla nasıl etkin şekilde deploy edersiniz. Pratik pattern'ler, yaygın tuzaklar ve her yaklaşım için en iyi çalışan yöntemler.

Fargate hakkında üç yazıdan sonra (101, 102, 103), "güzel de, bunları AWS Console'da tıklayarak değil de nasıl deploy edeceğim, 2015'te değiliz" diye düşünüyor olabilirsiniz.

Fargate servislerini deploy etmek, ekibiniz ve gereksinimleriniz için doğru Infrastructure as Code (IaC) aracını seçmeyi gerektirir. Her yaklaşım karmaşıklık, bakım yapılabilirlik ve geliştirici deneyiminde farklı trade-off'lar sunar.

Fargate için IaC Araç Karşılaştırması

CloudFormation - Temel

yaml
# Verbose ama kapsamlıResources:  TaskDefinition:    Type: AWS::ECS::TaskDefinition    Properties:      Family: my-app      NetworkMode: awsvpc      RequiresCompatibilities:        - FARGATE      Cpu: '256'      Memory: '512'      # Detaylı konfigürasyon gerektirir

Terraform - Endüstri Standardı

hcl
# Deklaratif ve açıkresource "aws_ecs_task_definition" "app" {  family                   = "my-app"  network_mode            = "awsvpc"  requires_compatibilities = ["FARGATE"]  cpu                     = "256"  memory                  = "512"  # Okunabilirlik ve kontrol arasında iyi denge}

CDK - Programlama Yaklaşımı

typescript
// Programlama yapılarıyla high-level soyutlamalarconst taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {  memoryLimitMiB: 512,  cpu: 256,});

Her yaklaşımda neyin iyi çalıştığını keşfedelim.

CDK ile Fargate Deploy Etmek

AWS CDK (Cloud Development Kit) altyapıyı TypeScript, Python, Java veya C# ile yazmanıza izin veriyor. CDK, Fargate deploymentları için yüksek seviye soyutlamalar sağlar.

Fargate için CDK Avantajları

typescript
import * as cdk from 'aws-cdk-lib';import * as ecs from 'aws-cdk-lib/aws-ecs';import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns';
export class FargateStack extends cdk.Stack {  constructor(scope: Construct, id: string, props?: cdk.StackProps) {    super(scope, id, props);
    // Bu tek construct şunları yaratıyor:    // - VPC, Subnet'ler, NAT Gateway'ler    // - ECS Cluster    // - Fargate Service    // - Application Load Balancer    // - Task Definition    // - Security Group'lar    // - CloudWatch Logs    const fargateService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'Service', {      taskImageOptions: {        image: ecs.ContainerImage.fromRegistry('nginx'),        containerPort: 80,        environment: {          NODE_ENV: 'production',          API_URL: 'https://api.example.com'        }      },      desiredCount: 3,      domainName: 'app.example.com',      domainZone: hostedZone,      certificate: certificate,    });
    // Auto-scaling ekle    const scaling = fargateService.service.autoScaleTaskCount({      maxCapacity: 10,      minCapacity: 2,    });
    scaling.scaleOnCpuUtilization('CpuScaling', {      targetUtilizationPercent: 50,    });
    // CloudWatch alarm'ları ekle    new cloudwatch.Alarm(this, 'HighMemory', {      metric: fargateService.service.metricMemoryUtilization(),      threshold: 80,      evaluationPeriods: 2,    });  }}

20 satır CDK'nın aslında yarattığı:

  • ~300 satır CloudFormation
  • 15+ AWS kaynağı
  • Tüm IAM role ve policy'ler
  • Düzgün security group kuralları
  • CloudWatch log group'ları

Fargate-Spesifik CDK Pattern'leri

1. Ortam Varyasyonlarıyla Servis Template'leri

typescript
interface FargateServiceProps {  serviceName: string;  image: string;  environment: 'dev' | 'staging' | 'prod';  port?: number;}
class FargateService extends Construct {  constructor(scope: Construct, id: string, props: FargateServiceProps) {    super(scope, id);
    // Ortam-spesifik boyutlandırma    const configs = {      dev: { cpu: 256, memory: 512, desiredCount: 1 },      staging: { cpu: 512, memory: 1024, desiredCount: 2 },      prod: { cpu: 1024, memory: 2048, desiredCount: 5 }    };
    const config = configs[props.environment];
    const service = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'Service', {      taskImageOptions: {        image: ecs.ContainerImage.fromRegistry(props.image),        containerPort: props.port || 80,      },      cpu: config.cpu,      memoryLimitMiB: config.memory,      desiredCount: config.desiredCount,      // ALB, VPC, subnet'ler, security group'ları otomatik yapılandır    });
    // Fargate-spesifik monitoring ekle    this.addFargateMonitoring(service);  }
  private addFargateMonitoring(service: ecsPatterns.ApplicationLoadBalancedFargateService) {    // Memory utilization alarmı    new cloudwatch.Alarm(this, 'MemoryAlarm', {      metric: service.service.metricMemoryUtilization(),      threshold: 80,      evaluationPeriods: 2,    });
    // Task count alarmı    new cloudwatch.Alarm(this, 'TaskCountAlarm', {      metric: service.service.metricDesiredCount(),      threshold: 1,      comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN,    });  }}

2. CDK ile Fargate Spot İşleme

typescript
// CDK high-level construct'larda Fargate Spot'u doğrudan desteklemiyor// Escape hatch'ler kullanman gerekiyorconst service = new ecs.FargateService(this, 'Service', {  cluster,  taskDefinition,  capacityProviderStrategies: [    {      capacityProvider: 'FARGATE_SPOT',      weight: 4,      base: 0,    },    {      capacityProvider: 'FARGATE',      weight: 1,      base: 2, // Her zaman 2'sini normal Fargate'te tut    }  ],});

Fargate için CDK Tuzakları

Sorun: ENI Limitleri

typescript
// CDK ENI'leri tüketen birçok kaynak yaratır// İzle ve alert'ler kurconst eniUsageMetric = new cloudwatch.Metric({  namespace: 'Custom/VPC',  metricName: 'ENIsInUse',});
new cloudwatch.Alarm(this, 'ENIUsage', {  metric: eniUsageMetric,  threshold: 4500, // Default 5000 limitinin %90'ı});

Terraform ile Fargate Deploy Etmek

Terraform mükemmel state yönetimiyle açık, öngörülebilir Fargate deploymentları sağlar. Fargate altyapınızı etkili şekilde nasıl yapılandıracağınız:

Terraform Fargate Temelleri

hcl
resource "aws_ecs_cluster" "main" {  name = "production"    setting {    name  = "containerInsights"    value = "enabled"  }}
resource "aws_ecs_task_definition" "app" {  family                   = "my-app"  network_mode            = "awsvpc"  requires_compatibilities = ["FARGATE"]  cpu                     = "512"  memory                  = "1024"  execution_role_arn      = aws_iam_role.ecs_task_execution_role.arn  task_role_arn          = aws_iam_role.ecs_task_role.arn
  container_definitions = jsonencode([{    name  = "app"    image = "nginx:latest"        portMappings = [{      containerPort = 80      protocol      = "tcp"    }]        logConfiguration = {      logDriver = "awslogs"      options = {        awslogs-group         = aws_cloudwatch_log_group.app.name        awslogs-region        = var.aws_region        awslogs-stream-prefix = "ecs"      }    }        environment = [      {        name  = "NODE_ENV"        value = "production"      }    ]  }])}
resource "aws_ecs_service" "app" {  name            = "my-app-service"  cluster         = aws_ecs_cluster.main.id  task_definition = aws_ecs_task_definition.app.arn  desired_count   = var.app_count  launch_type     = "FARGATE"
  # Otomatik task definition güncellemeleri için track_latest kullan  task_definition_track_latest = true
  network_configuration {    security_groups  = [aws_security_group.ecs_tasks.id]    subnets          = aws_subnet.private[*].id    assign_public_ip = false  }
  load_balancer {    target_group_arn = aws_alb_target_group.app.arn    container_name   = "app"    container_port   = 80  }
  depends_on = [aws_alb_listener.front_end]}

Aklımızı Kurtaran Module Pattern'i

hcl
# modules/fargate-service/main.tfvariable "service_name" {}variable "image" {}variable "cpu" { default = "256" }variable "memory" { default = "512" }variable "desired_count" { default = 2 }
# ... 200 satır tekrar kullanılabilir Terraform ...
output "service_url" {  value = aws_alb.main.dns_name}
# Ana konfigürasyonunuzdamodule "api_service" {  source        = "./modules/fargate-service"  service_name  = "api"  image        = "myapp/api:latest"  cpu          = "512"  memory       = "1024"  desired_count = 3}
module "worker_service" {  source        = "./modules/fargate-service"  service_name  = "worker"  image        = "myapp/worker:latest"  cpu          = "256"  memory       = "512"  desired_count = 5}

Temel State Yönetimi

Düzgün state yönetimi Terraform deploymentları için kritiktir. Eski state dosyaları istenmeyen kaynak yok etmeye yol açabilir.

bash
# Plan output'unu her zaman dikkatli inceleyin$ terraform planTerraform will perform the following actions:  # aws_ecs_service.app will be destroyed  - resource "aws_ecs_service" "app" {      - name = "production-api" -> null      # ... 50 kaynak yok edilecek  }
Plan: 0 to add, 0 to change, 52 to destroy.
# Production'da asla auto-approve kullanmayın$ terraform apply  # Manuel olarak inceleyin ve onaylayın

Gerekli: Ekip ortamları için her zaman remote state kullanın.

hcl
terraform {  backend "s3" {    bucket         = "terraform-state-prod"    key            = "fargate/terraform.tfstate"    region         = "us-east-1"    dynamodb_table = "terraform-locks"    encrypt        = true  }}

SAM: Lambda-First Yaklaşım

AWS SAM (Serverless Application Model) Lambda için harika, ama Fargate için? Çivi çakmak için tornavida kullanmak gibi.

yaml
# template.yamlTransform: AWS::Serverless-2016-10-31
Resources:  FargateCluster:    Type: AWS::ECS::Cluster    TaskDefinition:    Type: AWS::ECS::TaskDefinition    Properties:      RequiresCompatibilities:        - FARGATE      NetworkMode: awsvpc      Cpu: '256'      Memory: '512'      # CloudFormation verbosity'sine geri dönüş    # SAM Lambda'yı Fargate ile karıştırdığınızda parlıyor  ProcessorFunction:    Type: AWS::Serverless::Function    Properties:      Handler: index.handler      Runtime: python3.12      Events:        ECSTask:          Type: CloudWatchEvent          Properties:            Pattern:              source:                - aws.ecs              detail-type:                - ECS Task State Change

SAM Fargate için ne zaman mantıklı:

  • Öncelikli olarak Lambda tabanlıysanız, biraz Fargate var
  • Step Functions orchestration'a ihtiyacınız var
  • Diğer servisler için zaten SAM'e yatırım yapmışsınız

Ne zaman değil:

  • Fargate birincil compute'unuz
  • Karmaşık networking'e ihtiyacınız var
  • Programlama dili özelliklerini istiyorsunuz

Migration Stratejileri

CloudFormation'dan Terraform Migration'ı

Mevcut altyapıyı migrate etmek dikkatli planlama gerektirir. Bu zorlukları göz önünde bulundurun:

Migration Süreci:

  1. Mevcut kaynakları export et
  2. Eşdeğer Terraform yaz
  3. Kaynakları dikkatli şekilde import et
  4. CloudFormation'ı kaldırmadan önce doğrula

Yaygın Sorunlar:

bash
$ terraform import aws_ecs_service.app production-app-serviceImport successful!
$ terraform plan~ 147 kaynak değiştirilecek  # Kaynak drift tespiti! 23 kaynak yeniden yaratılacak  # Breaking değişiklikler
Error: Resource already exists  # Import çakışmaları

En İyi Uygulamalar:

  • Kritik olmayan kaynaklarla başla
  • Hedeflenen apply'lar kullan: terraform apply -target=resource
  • Geçiş sırasında paralel stack'ler çalıştır
  • Kaynak keşfi ve import için script'ler

Terraform'dan CDK Migration'ı

CDK migration'ları import sınırlarıyla karşılaşır:

typescript
class MigrationStack extends cdk.Stack {  constructor(scope: Construct, id: string) {    super(scope, id);
    // Sınırlı import desteği    const cluster = ecs.Cluster.fromClusterArn(      this,      'ImportedCluster',      'arn:aws:ecs:us-east-1:123456789:cluster/production'    );
    // CDK import sınırları:    // - Task definition'lar yeniden yaratım gerektirir    // - Karmaşık servis konfigürasyonları    // - Service discovery entegrasyonu  }}

Migration Stratejisi: Karmaşık geçişler için her iki aracı da geçici olarak çalıştırmayı düşünün.

Karar Matrisi

Doğru IaC aracını seçmek için rehber:

CDK'yı seçin eğer:

  • Ekibiniz TypeScript/Python'u iyi biliyor
  • Sıfırdan başlıyorsunuz (legacy yok)
  • High-level abstraction'lar istiyorsunuz
  • AWS'ye all-in'siniz
  • Uçta yaşamayı seviyorsunuz

Terraform'u seçin eğer:

  • Multi-cloud potansiyeline ihtiyacınız var
  • Ekibiniz declarative syntax tercih ediyor
  • Mevcut Terraform module'leriniz var
  • Stabilite > En son özellikler
  • Büyük community desteğine değer veriyorsunuz

SAM'i seçin eğer:

  • Lambda-first mimarideyseniz
  • Step Functions'a ihtiyacınız var
  • Minimal tooling istiyorsunuz
  • Fargate kullanımınız minimal

Hala CloudFormation kullanın eğer:

  • Acıdan hoşlanıyorsanız (şaka!)
  • AWS Support'un debug etmesine ihtiyacınız var
  • AWS Service Catalog kullanıyorsunuz
  • Kurumsal zorunluluk (başınız sağ olsun)

Her Yerde İşe Yarayan Pattern'ler

Tool'dan bağımsız, bu pattern'ler bizi kurtardı:

1. Environment Abstraction'ı

typescript
// CDKinterface EnvironmentConfig {  cpu: number;  memory: number;  desiredCount: number;  environment: Record<string, string>;}
const configs: Record<string, EnvironmentConfig> = {  dev: { cpu: 256, memory: 512, desiredCount: 1 },  staging: { cpu: 512, memory: 1024, desiredCount: 2 },  prod: { cpu: 1024, memory: 2048, desiredCount: 5 }};
hcl
# Terraformlocals {  env_config = {    dev     = { cpu = 256, memory = 512, count = 1 }    staging = { cpu = 512, memory = 1024, count = 2 }    prod    = { cpu = 1024, memory = 2048, count = 5 }  }    config = local.env_config[var.environment]}

2. Service Template Pattern'i

Kod kopyalamak yerine, template'ler yaratın:

typescript
// CDK: Base service constructexport class BaseEcsService extends Construct {  public readonly service: ecs.FargateService;    constructor(scope: Construct, id: string, props: BaseEcsServiceProps) {    super(scope, id);        // 100 satır boilerplate    this.service = new ecs.FargateService(this, 'Service', {      // Ortak konfigürasyon    });        // Standart alarm'lar    this.setupAlarms();        // Standart dashboard    this.setupDashboard();  }}
// Kullanımnew BaseEcsService(this, 'ApiService', {  image: 'api:latest',  port: 3000,  cpu: 512});

3. GitOps Pipeline

yaml
# .github/workflows/deploy.ymlname: Deploy Infrastructure
on:  push:    branches: [main]    paths:      - 'infrastructure/**'
jobs:  plan:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4            - name: Terraform Plan        run: |          cd infrastructure          terraform init          terraform plan -out=tfplan                - name: Post Plan to PR        uses: actions/github-script@v6        with:          script: |            // Plan output'u PR comment olarak post et              apply:    needs: plan    if: github.ref == 'refs/heads/main'    steps:      - name: Terraform Apply        run: |          terraform apply tfplan

Her Yaklaşımın Maliyeti

Para konuşalım, çünkü cloud faturaları yalan söylemez:

ToolÖğrenme EğrisiBakım MaliyetiEsneklikAWS Özellik Gecikmesi
CDK2 haftaOrtaYüksek0-2 hafta
Terraform1 haftaDüşükYüksek2-4 hafta
SAM3 günDüşükDüşük0 hafta
CloudFormation1 haftaYüksekOrta0 hafta

Ama gerçek maliyet? Developer mutluluğu.

Ekip hızımız:

  • CloudFormation ile: 5 story point/sprint
  • Terraform ile: 8 story point/sprint
  • CDK ile: 12 story point/sprint

Sonuç

Farklı senaryolar için iyi çalışan:

  • Yeni projeler: TypeScript ile CDK
  • Mevcut projeler: Zaten orada olan (mecbur kalmadıkça migrate etmeyin)
  • Multi-cloud potansiyeli: Terraform
  • Hızlı prototip: SAM
  • Bir daha asla: Raw CloudFormation

Kirli sır? Hepsi zaten CloudFormation üretiyor. Ekibinizi üretken yapan abstraction seviyesini seçin.

Unutmayın: En iyi IaC tool'u ekibinizin gerçekten kullanacağı tool'dur. Mükemmelin, deploy edilenin düşmanı olmasına izin vermeyin.

AWS Fargate Derinlemesine Serisi

AWS Fargate'e temellerden production'a tam rehber. Gerçek dünya deneyimleri ile serverless container'ları, maliyet optimizasyonu, debugging tekniklerini ve Infrastructure-as-Code deployment pattern'lerini öğrenin.

İlerleme4/4 yazı tamamlandı

İlgili Yazılar