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.

İyi soru. Size 50+ Fargate servisini console üzerinden yönetmeye çalıştığımız zamanı anlatayım. Spoiler: iyi bitmedi.

Fargate IaC Yolculuğumuzun Evrimi#

Yıl 1: CloudFormation (Karanlık Çağ)

YAML
# Geliştiricileri ağlatan 500 satır YAML
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: my-app
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      Cpu: '256'
      Memory: '512'
      # ... 50 satır daha boilerplate

Yıl 2: Terraform (Rönesans)

hcl
# En azından okunabiliyordu
resource "aws_ecs_task_definition" "app" {
  family                   = "my-app"
  network_mode            = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                     = "256"
  memory                  = "512"
  # Hala verbose, ama yönetilebilir
}

Yıl 3: CDK (Aydınlanma)

TypeScript
// Sonunda, gerçek programlama
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
  memoryLimitMiB: 512,
  cpu: 256,
});

Zor yoldan öğrendiklerimizi paylaşayım.

CDK: Altyapınızı Kodlamak İstediğinizde#

AWS CDK (Cloud Development Kit) altyapıyı TypeScript, Python, Java veya C# ile yazmanıza izin veriyor. İki yıl yoğun kullanımdan sonra, dürüst görüşüm.

İyi Yanı: Gerçek Programlama#

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ı

Kötü Yanı: Abstraction Sızıntıları#

Abstraction'ların sızıntılı olduğunu söylemiştim ya? CDK bir sızıntı yangın hortumu.

TypeScript
// Bu yeterince masum görünüyor
const cluster = new ecs.Cluster(this, 'Cluster', {
  vpc: myVpc,
});

// Ama sonra CDK'nın expose etmediği bir şey için escape hatch gerekiyor
const cfnCluster = cluster.node.defaultChild as ecs.CfnCluster;
cfnCluster.capacityProviders = ['FARGATE_SPOT'];

// Ve aniden TypeScript'te CloudFormation yazıyorsunuz

Çirkin Yanı: Versiyon Cehennemi#

JSON
{
  "dependencies": {
    "aws-cdk-lib": "2.100.0",  // Bunu güncelle...
    "@aws-cdk/aws-ecs-patterns": "2.100.0",  // ...bu bozulur
    "constructs": "^10.0.0"  // ...bu da çakışır
  }
}

Bir keresinde CDK deploy'umuzun neden aniden çalışmayı durdurduğunu debug etmek için 3 gün harcadık. Meğer minor versiyon güncellemesi VPC subnet'lerinin nasıl seçildiğini değiştirmiş. Eğlenceli zamanlar.

Terraform: Endüstri Standardı#

Terraform IaC araçlarının İsviçre'si gibi - tarafsız, güvenilir ve herkes kabul ediyor.

İyi Yanı: Tahmin Edilebilirlik#

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"

  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.tf
variable "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ürasyonunuzda
module "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
}

State File Korku Hikayesi#

Size birinin 3 haftalık state file'ı olan laptop'tan terraform apply çalıştırdığı zamanı anlatayım...

Bash
# Sabah masum başladı
$ terraform plan
Terraform 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.

# Birisi plan output'unu okumadı
$ terraform apply -auto-approve

# 5 dakika sonra: production çöktü

Öğrenilen ders: Her zaman remote state kullanın. Her zaman.

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.yaml
Transform: 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.9
      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 Hikayeleri#

Hikaye 1: CloudFormation'dan Terraform'a (6 ay acı)#

200+ CloudFormation stack'imiz vardı. Migration planı basit görünüyordu:

  1. Mevcut kaynakları export et
  2. Eşdeğer Terraform yaz
  3. Kaynakları import et
  4. CloudFormation stack'lerini sil

Gerçeklik:

Bash
# Ay 1: Güven
$ terraform import aws_ecs_service.app production-app-service
Import successful!

# Ay 2: Gerçeklik vuruyor
$ terraform plan
~ 147 kaynak değiştirilecek
! 23 kaynak yeniden yaratılacak

# Ay 3: Drift
Error: Resource already exists

# Ay 4: Workaround script'leri
$ python cloudformation_to_terraform.py --dua-et

# Ay 5: Kabullenme
$ terraform apply -target=aws_ecs_service.app

# Ay 6: Zafer (bir nevi)
$ aws cloudformation delete-stack --stack-name old-stack-47-of-200

Hikaye 2: Terraform'dan CDK'ya (Vaat Edilmiş Topraklar?)#

TypeScript
// CDK'nın daha iyi olacağını düşündük
class LegacyInfraStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    
    // Mevcut kaynakları import et
    const cluster = ecs.Cluster.fromClusterArn(
      this,
      'ImportedCluster',
      'arn:aws:ecs:us-east-1:123456789:cluster/production'
    );
    
    // Bu yaklaşık 5 kaynak için çalıştı
    // Sonra buna çarptık:
    
    // CDK task definition import'u desteklemiyor
    // CDK birden fazla target group'lu service import'u desteklemiyor
    // CDK service registry'li service import'u desteklemiyor
    // CDK desteklemiyor...
  }
}

Bir yıl boyunca hem Terraform hem CDK çalıştırdık. Tavsiye etmem.

Karar Matrisi#

Tüm bu savaşlardan sonra, dürüst tavsiyem:

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
// CDK
interface 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
# Terraform
locals {
  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 construct
export 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ım
new BaseEcsService(this, 'ApiService', {
  image: 'api:latest',
  port: 3000,
  cpu: 512
});

3. GitOps Pipeline#

YAML
# .github/workflows/deploy.yml
name: Deploy Infrastructure

on:
  push:
    branches: [main]
    paths:
      - 'infrastructure/**'

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - 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ç#

Üç yıl ve dört farklı IaC tool'undan sonra, gerçekte kullandığım:

  • 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ı
Loading...

Yorumlar (0)

Sohbete katıl

Düşüncelerini paylaşmak ve toplulukla etkileşim kurmak için giriş yap

Henüz yorum yok

Bu yazı hakkında ilk düşüncelerini paylaşan sen ol!

Related Posts