İçeriğe atla

2025-09-04

Serverless Framework'ten AWS CDK'ya Geçiş: Bölüm 6 - Production İpuçları

CDK migration'dan öğrenilen production dersleri. Monitoring, cost optimization ve troubleshooting.

Bir CDK migrasyonunun son aşaması üretilen altyapının doğruluğu değil, kesme anındaki operasyonel hazırlıktır: trafiği almak için bir plan, migrasyon üretimi bozarsa geri dönmek için bir plan ve canlı yük altında çıkan herhangi bir drift’i uzlaştırmak için bir plan. Onlarca Lambda fonksiyonu ve birden fazla DynamoDB tablosunu kapsayan bir migrasyon için kesme planı, migrasyon kodunun kendisinden büyüktür; geri dönüş hızlı, granüler ve production’a yük taşınmadan önce test edilmiş olmalıdır.

Bu yazı, Serverless Framework’ten CDK’ya migrasyon serisinin son parçasıdır. Production kesme stratejisini, servis başına rollback planını, migrasyon sırasında hata bütçelerini güvende tutan trafik şekillendirme desenlerini (canary, blue-green), veri migrasyonu uzlaştırma adımını ve eski ve yeni sistemlerin aynı davranışı yaydığını doğrulayan migrasyon sonrası doğrulamayı kapsar.

Seri Navigasyonu:

Üç Migration Yaklaşımı ve Sonuçları

Production ortamlarında üç farklı migration stratejisi test edildi, her biri değerli içgörüler sağladı:

Yaklaşım #1: Big Bang Migration

Uygulama: Tüm CDK altyapısını 4 saatlik bakım penceresi sırasında dağıtma.

Karşılaşılan sorunlar: CloudFormation stack dağıtımı zaman tahminlerini aştı (6 saat). API Gateway stage deployment başarısız oldu. DynamoDB içe aktarma 3.000 kayıtta veri bütünlüğü sorunu yaşadı. Rollback ek 4 saat gerektirdi.

Operasyonel etki: Toplam 10 saat kesinti, önemli servis aksamaları, artan destek talebi.

Ders: “Big bang” demo app’ler için işe yarar, interdependency’leri olan production sistemler için değil.

Yaklaşım #2: Strangler Pattern Uygulaması

Uygulama: Traffic splitting ile kademeli fonksiyon migration.

Karşılaşılan sorunlar: Karmaşık fonksiyon bağımlılıkları cross-service çağrı desenleri oluşturdu. Sistemler arası kimlik doğrulama senkronizasyonu başarısız oldu. Artan gecikme nedeniyle performans düşüşü.

Operasyonel etki: Migration süresi 3 haftadan 2 aya uzadı. API performans sorunları bildirildi.

Ders: Strangler pattern dikkatli dependency mapping ve paylaşılan authentication gerektiriyor.

Yaklaşım #3: Başarılı Blue-Green Deployment

Uygulama: Anında traffic switching ile tam paralel deployment.

Sonuçlar: Tam ortam paritesi sağlandı. 30 saniyelik rollback yeteneği. Veri kaybı yok. Kesinti yok.

Operasyonel etki: Kesinti olmadan başarılı migration. Performans %40 iyileşti. Servis kesintisi yok.

Etkili yaklaşım: Kapsamlı monitoring ve otomatik rollback ile blue-green deployment.

Production Hazır Migration Stratejileri

Blue-Green Deployment Stratejisi

Blue-green deployment, production migration’ları için en etkili yaklaşım olarak kanıtlandı:

// lib/stacks/production-blue-green-stack.ts
import { Stack, StackProps, Tags, CfnOutput, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { RestApi, Deployment, Stage, MethodLoggingLevel, LambdaIntegration } from 'aws-cdk-lib/aws-apigateway';
import { Alarm, Metric, ComparisonOperator, TreatMissingData } from 'aws-cdk-lib/aws-cloudwatch';
import { LambdaAction } from 'aws-cdk-lib/aws-cloudwatch-actions';
import { PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';

export interface BlueGreenStackProps extends StackProps {
  stage: string;
  environment: 'blue' | 'green';
  monitoringConfig: {
    errorThreshold: number;
    latencyThreshold: number;
    rollbackFunction: NodejsFunction;
  };
}

export class ProductionBlueGreenStack extends Stack {
  public readonly api: RestApi;
  public readonly healthCheckEndpoint: string;
  public readonly switchOverFunction: NodejsFunction;

  constructor(scope: Construct, id: string, props: BlueGreenStackProps) {
    super(scope, id, props);

    // Tam CDK infrastructure oluştur
    this.api = new RestApi(this, 'Api', {
      restApiName: `my-service-${props.stage}-${props.environment}`,
      description: `Production API - ${props.environment.toUpperCase()} environment`,
      deployOptions: {
        stageName: props.environment,
        // Migration sırasında güvenlik için agresif throttling
        throttlingRateLimit: props.environment === 'green' ? 500 : 1000,
        throttlingBurstLimit: props.environment === 'green' ? 1000 : 2000,
        // Migration sırasında gelişmiş monitoring
        metricsEnabled: true,
        loggingLevel: MethodLoggingLevel.INFO,
        dataTraceEnabled: true,
        tracingEnabled: true,
      },
    });

    // Tüm Lambda fonksiyonlarını deploy et
    const functions = this.createLambdaFunctions(props);

    // API route'ları kur
    this.setupApiRoutes(functions);

    // Monitoring için health check endpoint oluştur
    const healthCheckFn = new NodejsFunction(this, 'HealthCheckFunction', {
      entry: 'src/health/health-check.ts',
      handler: 'handler',
      environment: {
        ENVIRONMENT: props.environment,
        API_VERSION: process.env.API_VERSION || 'v1',
        DEPLOYMENT_TIME: new Date().toISOString(),
      },
    });

    const healthResource = this.api.root.addResource('health');
    healthResource.addMethod('GET', new LambdaIntegration(healthCheckFn));

    this.healthCheckEndpoint = `${this.api.url}health`;

    // Production monitoring alarm'ları oluştur
    this.createProductionAlarms(props);

    // Traffic switching fonksiyonu
    this.switchOverFunction = this.createSwitchOverFunction(props);

    // Tanımlama için tüm kaynakları tagla
    Tags.of(this).add('Environment', props.environment);
    Tags.of(this).add('MigrationPhase', 'cdk-migration');
    Tags.of(this).add('DeploymentTime', new Date().toISOString());
    Tags.of(this).add('Version', process.env.COMMIT_SHA || 'latest');

    // Kritik bilgileri export et
    new CfnOutput(this, 'ApiEndpoint', {
      value: this.api.url,
      exportName: `${this.stackName}-api-endpoint`,
      description: `API endpoint for ${props.environment} environment`,
    });

    new CfnOutput(this, 'HealthCheckUrl', {
      value: this.healthCheckEndpoint,
      exportName: `${this.stackName}-health-check`,
      description: 'Health check endpoint for monitoring',
    });
  }

  private createProductionAlarms(props: BlueGreenStackProps) {
    // Error rate alarm - rollback tetikler
    const errorAlarm = new Alarm(this, 'HighErrorRateAlarm', {
      metric: this.api.metricServerError({
        period: Duration.minutes(2),
        statistic: 'Sum',
      }),
      threshold: props.monitoringConfig.errorThreshold,
      evaluationPeriods: 2,
      comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
      alarmDescription: `High error rate detected in ${props.environment} environment`,
      treatMissingData: TreatMissingData.NOT_BREACHING,
    });

    // Latency alarm - araştırma tetikler
    const latencyAlarm = new Alarm(this, 'HighLatencyAlarm', {
      metric: this.api.metricLatency({
        period: Duration.minutes(5),
        statistic: 'Average',
      }),
      threshold: props.monitoringConfig.latencyThreshold,
      evaluationPeriods: 3,
      alarmDescription: `High latency detected in ${props.environment} environment`,
    });

    // Alarm'ları otomatik rollback'e bağla
    errorAlarm.addAlarmAction(
      new LambdaAction(props.monitoringConfig.rollbackFunction)
    );

    // External monitoring için alarm ARN'lerini export et
    new CfnOutput(this, 'ErrorAlarmArn', {
      value: errorAlarm.alarmArn,
      exportName: `${this.stackName}-error-alarm`,
    });
  }

  private createSwitchOverFunction(props: BlueGreenStackProps) {
    return new NodejsFunction(this, 'TrafficSwitchFunction', {
      entry: 'src/deployment/traffic-switch.ts',
      handler: 'handler',
      timeout: Duration.minutes(5),
      environment: {
        CURRENT_ENVIRONMENT: props.environment,
        TARGET_ENVIRONMENT: props.environment === 'blue' ? 'green' : 'blue',
        HOSTED_ZONE_ID: process.env.HOSTED_ZONE_ID!,
        DOMAIN_NAME: process.env.API_DOMAIN!,
        SLACK_WEBHOOK_URL: process.env.SLACK_WEBHOOK_URL!,
      },
      initialPolicy: [
        new PolicyStatement({
          actions: ['route53:ChangeResourceRecordSets', 'route53:GetChange'],
          resources: ['*'],
        }),
      ],
    });
  }
}

// src/health/health-check.ts - Kapsamlı health validation
import { APIGatewayProxyHandler } from 'aws-lambda';
import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';

const dynamoDB = new DynamoDBClient({});

export const handler: APIGatewayProxyHandler = async () => {
  const startTime = Date.now();
  const checks = [];

  try {
    // Database connectivity check
    const tableCheck = await dynamoDB.send(new DescribeTableCommand({
      TableName: process.env.USERS_TABLE!,
    }));
    checks.push({
      name: 'database',
      status: tableCheck.Table?.TableStatus === 'ACTIVE' ? 'healthy' : 'unhealthy',
      responseTime: Date.now() - startTime,
    });

    // Memory usage check
    const memoryUsed = process.memoryUsage();
    checks.push({
      name: 'memory',
      status: memoryUsed.heapUsed < 100 * 1024 * 1024 ? 'healthy' : 'warning', // 100MB threshold
      details: {
        heapUsed: Math.round(memoryUsed.heapUsed / 1024 / 1024) + 'MB',
        heapTotal: Math.round(memoryUsed.heapTotal / 1024 / 1024) + 'MB',
      },
    });

    const overallStatus = checks.every(check => check.status === 'healthy') ? 'healthy' : 'degraded';

    return {
      statusCode: overallStatus === 'healthy' ? 200 : 503,
      headers: {
        'Content-Type': 'application/json',
        'Cache-Control': 'no-cache',
      },
      body: JSON.stringify({
        status: overallStatus,
        environment: process.env.ENVIRONMENT,
        version: process.env.API_VERSION,
        deploymentTime: process.env.DEPLOYMENT_TIME,
        timestamp: new Date().toISOString(),
        responseTime: Date.now() - startTime,
        checks,
      }),
    };
  } catch (error) {
    return {
      statusCode: 503,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        status: 'unhealthy',
        error: error.message,
        timestamp: new Date().toISOString(),
      }),
    };
  }
};

2. Strangler Fig Pattern

Ne zaman kullanılır: Sıfır kesinti gerektiren büyük uygulamalar.

Canary deployment ile traffic split: percentTraffic ile yeni API’ye kademeli geçiş. CloudWatch alarmları hata eşiğinde rollback tetikler.

3. Blue-Green Deployment

Ne zaman kullanılır: Anında rollback kabiliyeti gerektiğinde.

Blue ve green stack’ler paralel deploy edilir. Route53 CNAME switch ile traffic anında değiştirilir. Tag’ler (Deployment: blue/green) ile kolay tanımlama.

Gerçekten Production Sorunlarını Yakalayan Test Stratejisi

İlk migration denemimiz başarısız oldu çünkü test suite’imiz kapsamlıydı ama yanlıştı. Production’da gerçekten bozulan şeyler hariç her şeyi test ettik.

Gerçeklik Kontrolü

Geleneksel test yaklaşımı: Unit testler, integration testler, load testler - hepsi geçiyor.

Production’da gerçekten başarısız olan:

  • CloudFormation template boyut limitleri (400KB aşıldı)
  • API Gateway 29 saniye timeout Lambda’nın 30 saniye timeout’una çarpıyor
  • Traffic spike’ları sırasında DynamoDB throttling
  • Load altında JWT token validation performansı

Production-Focused Test Stratejisi

İşte production’a çıkmadan önce gerçek sorunları yakalayan test yaklaşımı:

// test/infrastructure/api-stack.test.ts
import { Template, Match } from 'aws-cdk-lib/assertions';
import { App } from 'aws-cdk-lib';
import { ApiStack } from '../../lib/stacks/api-stack';

describe('ApiStack', () => {
  let template: Template;

  beforeAll(() => {
    const app = new App();
    const stack = new ApiStack(app, 'TestStack', {
      config: testConfig,
    });
    template = Template.fromStack(stack);
  });

  test('Lambda functions have correct runtime', () => {
    template.allResourcesProperties('AWS::Lambda::Function', {
      Runtime: 'nodejs20.x',
    });
  });

  test('API Gateway has throttling enabled', () => {
    template.hasResourceProperties('AWS::ApiGateway::Stage', {
      ThrottlingRateLimit: Match.anyValue(),
      ThrottlingBurstLimit: Match.anyValue(),
    });
  });

  test('DynamoDB tables have point-in-time recovery', () => {
    template.allResourcesProperties('AWS::DynamoDB::Table', {
      PointInTimeRecoverySpecification: {
        PointInTimeRecoveryEnabled: true,
      },
    });
  });
});

Integration Testing

// test/integration/api.test.ts
import { CloudFormationClient } from '@aws-sdk/client-cloudformation';
import { ApiGatewayClient } from '@aws-sdk/client-api-gateway';
import axios from 'axios';

describe('API Integration Tests', () => {
  let apiEndpoint: string;
  let authToken: string;

  beforeAll(async () => {
    // Deploy edilmiş API endpoint'ini al
    const cf = new CloudFormationClient({});
    const exports = await cf.send(new ListExportsCommand({}));
    apiEndpoint = exports.Exports?.find(
      e => e.Name === 'ApiStack-endpoint'
    )?.Value!;

    // Auth token al
    authToken = await getTestAuthToken();
  });

  test('Health check endpoint', async () => {
    const response = await axios.get(`${apiEndpoint}/health`);
    expect(response.status).toBe(200);
    expect(response.data).toEqual({ status: 'healthy' });
  });

  test('Create and retrieve user', async () => {
    // User oluştur
    const createResponse = await axios.post(
      `${apiEndpoint}/users`,
      { name: 'Test User', email: '[email protected]' },
      { headers: { Authorization: `Bearer ${authToken}` } }
    );
    expect(createResponse.status).toBe(201);

    // User'ı getir
    const userId = createResponse.data.userId;
    const getResponse = await axios.get(
      `${apiEndpoint}/users/${userId}`,
      { headers: { Authorization: `Bearer ${authToken}` } }
    );
    expect(getResponse.data.name).toBe('Test User');
  });
});

Load Testing

// test/load/k6-script.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate } from 'k6/metrics';

const errorRate = new Rate('errors');

export const options = {
  stages: [
    { duration: '2m', target: 100 },  // Ramp up
    { duration: '5m', target: 100 },  // Sustain
    { duration: '2m', target: 200 },  // Spike
    { duration: '5m', target: 200 },  // Sustain spike
    { duration: '2m', target: 0 },  // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'], // Request'lerin 95%'i 500ms altında
    errors: ['rate<0.01'],  // Error oranı 1% altında
  },
};

export default function() {
  const response = http.get(`${__ENV.API_URL}/users`);

  const success = check(response, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });

  errorRate.add(!success);
  sleep(1);
}

Rollback Prosedürleri

Otomatik Rollback

// lib/constructs/deployment/safe-deployment.ts
export class SafeDeployment extends Construct {
  constructor(scope: Construct, id: string, props: {
    api: RestApi;
    alarmThreshold: number;
    rollbackFunction: IFunction;
  }) {
    super(scope, id);

    // CloudWatch alarm oluştur
    const alarm = new Alarm(this, 'DeploymentAlarm', {
      metric: props.api.metricServerError(),
      threshold: props.alarmThreshold,
      evaluationPeriods: 2,
      treatMissingData: TreatMissingData.NOT_BREACHING,
    });

    // Bildirimler için SNS topic
    const topic = new Topic(this, 'RollbackTopic');
    alarm.addAlarmAction(new SnsAction(topic));

    // Otomatik rollback için Lambda
    topic.addSubscription(
      new LambdaSubscription(props.rollbackFunction)
    );

    // Manuel rollback komutu
    new CfnOutput(this, 'RollbackCommand', {
      value: `aws lambda invoke --function-name ${props.rollbackFunction.functionName} --payload '{"action":"rollback"}' response.json`,
    });
  }
}

// src/deployment/rollback-handler.ts
export const handler = async (event: SNSEvent) => {
  console.log('Initiating rollback:', JSON.stringify(event, null, 2));

  const codedeploy = new CodeDeployClient({});

  // Mevcut deployment'ı durdur
  await codedeploy.send(new StopDeploymentCommand({
    deploymentId: process.env.CURRENT_DEPLOYMENT_ID,
    autoRollbackEnabled: true,
  }));

  // Traffic'i önceki versiyona döndür
  await switchTraffic('blue'); // Green başarısız olduğunu varsayarak

  // Ekibi bilgilendir
  await notifySlack({
    channel: '#alerts',
    message: 'Automatic rollback initiated due to high error rate',
  });
};

Performans Optimizasyonu

Lambda Performans Tuning

// lib/constructs/performance/optimized-function.ts
export class OptimizedFunction extends ServerlessFunction {
  constructor(scope: Construct, id: string, props: ServerlessFunctionProps & {
    enableProvisioning?: boolean;
    enableSnapStart?: boolean;
  }) {
    super(scope, id, {
      ...props,
      memorySize: props.memorySize || 1024,
      architecture: Architecture.ARM_64, // Daha iyi price/performance
      environment: {
        ...props.environment,
        NODE_OPTIONS: '--enable-source-maps --max-old-space-size=896',
        AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
      },
    });

    // Kritik fonksiyonlar için provisioned concurrency
    if (props.enableProvisioning && props.config.stage === 'prod') {
      const version = this.currentVersion;

      new CfnAlias(this, 'ProvisionedAlias', {
        functionName: this.functionName,
        functionVersion: version.version,
        name: 'provisioned',
        provisionedConcurrencyConfig: {
          provisionedConcurrentExecutions: 5,
        },
      });
    }

    // Java fonksiyonları için SnapStart
    if (props.enableSnapStart) {
      const cfnFunction = this.node.defaultChild as CfnFunction;
      cfnFunction.snapStart = {
        applyOn: 'PublishedVersions',
      };
    }
  }
}

API Gateway Optimizasyonu

// lib/constructs/performance/cached-api.ts
export class CachedApi extends RestApi {
  constructor(scope: Construct, id: string, props: RestApiProps & {
    cacheConfig?: {
      ttlMinutes: number;
      encrypted: boolean;
      clusterSize: string;
    };
  }) {
    super(scope, id, {
      ...props,
      deployOptions: {
        ...props.deployOptions,
        cachingEnabled: true,
        cacheClusterEnabled: true,
        cacheClusterSize: props.cacheConfig?.clusterSize || '0.5',
        cacheDataEncrypted: props.cacheConfig?.encrypted ?? true,
        cacheTtl: Duration.minutes(props.cacheConfig?.ttlMinutes || 5),
        methodOptions: {
          '/*/*': {
            cachingEnabled: true,
            cacheKeyParameters: [
              'method.request.path.proxy',
              'method.request.querystring.page',
            ],
          },
        },
      },
    });
  }
}

Monitoring ve Gözlemlenebilirlik

Kapsamlı Monitoring Stack

// lib/stacks/monitoring-stack.ts
export class MonitoringStack extends Stack {
  constructor(scope: Construct, id: string, props: {
    apiStack: ApiStack;
    stage: string;
  }) {
    super(scope, id);

    // Dashboard oluştur
    const dashboard = new Dashboard(this, 'ServiceDashboard', {
      dashboardName: `my-service-${props.stage}`,
    });

    // API metrikleri
    dashboard.addWidgets(
      new GraphWidget({
        title: 'API Requests',
        left: [props.apiStack.api.metricCount()],
        right: [props.apiStack.api.metricLatency()],
      }),
      new GraphWidget({
        title: 'API Errors',
        left: [
          props.apiStack.api.metric4XXError(),
          props.apiStack.api.metric5XXError(),
        ],
      })
    );

    // Lambda metrikleri
    const lambdaWidgets = props.apiStack.functions.map(fn =>
      new GraphWidget({
        title: `${fn.functionName} Performance`,
        left: [fn.metricInvocations()],
        right: [fn.metricDuration()],
      })
    );
    dashboard.addWidgets(...lambdaWidgets);

    // Alarmlar
    this.createAlarms(props.apiStack);
  }

  private createAlarms(apiStack: ApiStack) {
    // API Gateway alarmları
    new Alarm(this, 'HighErrorRate', {
      metric: apiStack.api.metric5XXError({
        period: Duration.minutes(5),
        statistic: 'Sum',
      }),
      threshold: 10,
      evaluationPeriods: 2,
    });

    // Lambda alarmları
    apiStack.functions.forEach(fn => {
      new Alarm(this, `${fn.node.id}Throttles`, {
        metric: fn.metricThrottles(),
        threshold: 5,
        evaluationPeriods: 2,
      });

      new Alarm(this, `${fn.node.id}Errors`, {
        metric: fn.metricErrors(),
        threshold: 10,
        evaluationPeriods: 2,
      });
    });
  }
}

Distributed Tracing

// lib/constructs/observability/tracing.ts
export class TracedFunction extends OptimizedFunction {
  constructor(scope: Construct, id: string, props: ServerlessFunctionProps) {
    super(scope, id, {
      ...props,
      tracing: Tracing.ACTIVE,
      environment: {
        ...props.environment,
        _X_AMZN_TRACE_ID: process.env._X_AMZN_TRACE_ID || '',
        AWS_XRAY_CONTEXT_MISSING: 'LOG_ERROR',
        AWS_XRAY_LOG_LEVEL: 'error',
      },
    });

    // X-Ray izinleri ekle
    this.addToRolePolicy(new PolicyStatement({
      actions: [
        'xray:PutTraceSegments',
        'xray:PutTelemetryRecords',
      ],
      resources: ['*'],
    }));
  }
}

// src/libs/tracing.ts
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = new Tracer({
  serviceName: process.env.SERVICE_NAME || 'my-service',
});

export function traceMethod(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  const originalMethod = descriptor.value;

  descriptor.value = async function(...args: any[]) {
    const segment = tracer.getSegment();
    const subsegment = segment?.addNewSubsegment(propertyKey);

    try {
      const result = await originalMethod.apply(this, args);
      subsegment?.close();
      return result;
    } catch (error) {
      subsegment?.addError(error as Error);
      subsegment?.close();
      throw error;
    }
  };

  return descriptor;
}

Migration Checklist’i

Pre-Migration

  • Mevcut kaynakları envantere al

    • Tüm Lambda fonksiyonlarını belgele
    • API Gateway endpoint’lerini listele
    • DynamoDB tablolarını ve indexlerini mapla
    • Custom kaynakları tanımla
    • Tüm environment variable’ları ve secret’ları not et
  • Dependency’leri değerlendir

    • Kullanımdaki Serverless plugin’lerini gözden geçir
    • Custom CloudFormation kaynaklarını kontrol et
    • External servis entegrasyonlarını tanımla
    • IAM role’leri ve policy’leri belgele
  • Migration stratejisini planla

    • Migration pattern’ı seç (big bang, strangler fig, blue-green)
    • Rollback prosedürlerini tanımla
    • Başarı kriterlerini belirle
    • Gerekirse maintenance window’ları planla

Migration Sırasında

  • CDK projesini kur

    • CDK ile repository’i initialize et
    • Environment’ları yapılandır
    • CI/CD pipeline’larını kur
    • Infrastructure testlerini implement et
  • Componentleri migrate et

    • Stateless kaynaklarla başla
    • Mevcut stateful kaynakları import et
    • Lambda fonksiyonlarını migrate et
    • API Gateway’i kur
    • Authentication’ı yapılandır
  • Testing

    • Unit testleri çalıştır
    • Integration testlerini yürüt
    • Load testing yap
    • Güvenlik konfigürasyonlarını validate et

Post-Migration

  • Monitor et ve optimize et

    • Kapsamlı monitoring kur
    • Alert’leri yapılandır
    • Performans metriklerini gözden geçir
    • Cold start’ları optimize et
  • Dokümantasyon

    • Runbook’ları güncelle
    • Yeni deployment prosedürlerini belgele
    • Mimari diyagramlar oluştur
    • Ekibi CDK konusunda eğit
  • Temizlik

    • Eski Serverless Framework kaynaklarını kaldır
    • Kullanılmayan IAM role’leri sil
    • S3 deployment bucket’larını temizle
    • DNS kayıtlarını güncelle

Yaygın Tuzaklar ve Çözümler

1. Kaynak Adlandırma Çakışmaları

// Hardcoded isimlerden kaçın
// Kötü
const table = new Table(this, 'Table', {
  tableName: 'users-table', // Varsa çakışır
});

// İyi
const table = new Table(this, 'Table', {
  tableName: `${props.serviceName}-${props.stage}-users`,
});

2. State Management

// Stateful ve stateless kaynakları ayır
const app = new App();

// Stateful kaynaklar ayrı stack'te
const dataStack = new DataStack(app, 'DataStack', {
  terminationProtection: true,
});

// Stateless kaynaklar serbestçe güncellenebilir
const apiStack = new ApiStack(app, 'ApiStack', {
  tables: dataStack.tables,
});

3. Environment Variable Migration

// Serverless variable'larını CDK'ya mapla
const legacyMappings: Record<string, string> = {
  '${self:service}': props.serviceName,
  '${opt:stage}': props.stage,
  '${opt:region}': Stack.of(this).region,
  '${cf:OtherStack.Output}': Fn.importValue('OtherStack-Output'),
};

Migration Sonuçları (4 Ay Sonra)

CDK migration dört aydır production’da çalışıyor. İşte ölçülen sonuçlar:

Performans İyileştirmeleri

  • API response zamanı: Ortalama 1.4s → 0.8s (43% iyileştirme)
  • Cold start azaltma: 850ms → 320ms (62% iyileştirme)
  • Authorization latency: 400ms → 12ms (97% iyileştirme)
  • Database query zamanı: 120ms → 45ms (optimize edilmiş connection pooling)

Maliyet Optimizasyonu

  • Aylık AWS maliyetleri: %32 azalma
  • Lambda maliyetleri: Memory optimizasyonu ile azaltıldı
  • DynamoDB maliyetleri: Query pattern’leri ile optimize edildi
  • CloudWatch maliyetleri: Structured logging ile azaltıldı

Operasyonel Mükemmellik

  • Deployment zamanı: 45 dakika → 12 dakika
  • Rollback zamanı: 4 saat → 30 saniye (blue-green deployment)
  • Güvenlik incident’ları: Ayda 2-3 → Ayda 0 (6 aydır devam ediyor)
  • Infrastructure bug’ları: Ayda 8 → Ayda 0.5 (95% azalma)

Developer Experience

  • Onboarding zamanı: 2 hafta → 2 saat (dokümantasyon + type safety)
  • Feature delivery: 2 hafta → 1 hafta (daha hızlı development cycle)
  • Bug araştırması: 3 saat → 20 dakika (daha iyi observability)
  • Cross-team dependency’ler: 5 ekip → 1 ekip (self-service infrastructure)

Operasyonel Etki

  • Servis sürekliliği: Kesintisiz migration başarıldı
  • Güvenlik uyumu: Tüm kurumsal gereksinimler karşılandı
  • Servis kalitesi: Migration kaynaklı sorun yok
  • Ekip verimliliği: İyileşmiş deployment güveni ve hızı

Önemli Migration İçgörüleri

Production migration birkaç önemli deseni ortaya çıkardı:

1. Blue-Green Deployment Production Güvenliği

İçgörü: Blue-green deployment en güvenilir production migration yolu sağlıyor. Sonuç: Anında rollback yeteneği ile kesintisiz migration.

2. Kapsamlı Health Check Gereksinimleri

İçgörü: Temel health check’ler kritik hata modlarını kaçırıyor. Sonuç: Detaylı validation sistemleri production sorunlarını önler.

3. Production Odaklı Test Yaklaşımı

İçgörü: Unit testler tek başına altyapı limitlerini veya edge case’leri yakalamıyor. Sonuç: Production odaklı testler deployment öncesi kritik sorunları tanımlar.

4. Performans Optimizasyonu Birleşiyor

İçgörü: CDK tüm stack katmanlarında optimizasyon sağlıyor. Sonuç: %43 genel performans iyileştirmesi elde edildi.

5. Infrastructure Code’da Tip Güvenliği

İçgörü: TypeScript yapılandırma hatalarını compile zamanında yakalar. Sonuç: Infrastructure ile ilgili bug’larda %95 azalma.

6. Risk Azaltma Olarak Monitoring

İçgörü: Kapsamlı monitoring güvenli migration’lar sağlar. Sonuç: Otomatik rollback sistemleri incident’ları önler.

7. Ekip Eğitimi Gereksinimleri

İçgörü: CDK, Serverless Framework’ten farklı kavramsal modeller gerektirir. Sonuç: Doğru eğitim önemli ölçüde daha hızlı development sağlar.

Kapsamlı Migration Kontrol Listesi

Hafta 1-2: Temel

  • CDK geliştirme ortamını kur
  • Production-grade proje yapısı oluştur
  • Kapsamlı test stratejisi uygula
  • Ekibi CDK desenleri ve TypeScript konusunda eğit

Hafta 3-4: Altyapı Migration’ı

  • Mevcut stateful kaynakları import et (DynamoDB, vb.)
  • Lambda fonksiyonlarını performans optimizasyonu ile migrate et
  • Uygun monitoring ile API Gateway kur
  • Authentication ve authorization implement et

Hafta 5-6: Güvenlik ve Uyumluluk

  • IAM izinlerini denetle ve düzelt (least privilege)
  • Secret yönetimini implement et
  • Kapsamlı logging ve monitoring kur
  • Güvenlik denetimini geç (gerekirse)

Hafta 7-8: Test ve Hazırlık

  • Blue-green deployment altyapısı oluştur
  • Otomatik rollback prosedürlerini implement et
  • Production-mirror load testing çalıştır
  • Health check kapsamını doğrula

Hafta 9-12: Migration Uygulaması

  • Green ortamını deploy et (CDK)
  • Paralel traffic validasyonu çalıştır
  • Monitoring ile traffic switch’i gerçekleştir
  • Legacy Serverless Framework kaynaklarını temizle

Post-Migration: Optimizasyon

  • Production metriklerine göre performans ayarı
  • Maliyet optimizasyonu (memory, provisioning, caching)
  • Dokümantasyon ve runbook güncellemeleri
  • Ekip retrospektifi ve dersler

Serverless Framework’te Kalmanın Uygun Olduğu Durumlar

Bazı senaryolar CDK’dan ziyade Serverless Framework’ten daha fazla fayda sağlar:

  1. Basit CRUD uygulamaları minimal customization ihtiyaçlarıyla
  2. Proof-of-concept projeler hızlı prototyping’e ihtiyaç duyan
  3. TypeScript deneyimi olmayan ekipler ve eğitim için bandwidth olmayan
  4. Heavy plugin dependency’leri olan uygulamalar CDK’da var olmayan
  5. YAML-only infrastructure policy’leri olan organizasyonlar

Sonuç: Infrastructure as Actual Code

Bu migration altyapı yönetimi yaklaşımlarını temel olarak değiştirdi. YAML yapılandırmasından TypeScript koduna geçiş, altyapıya derleme, test ve doğrulama getiriyor.

Migration süreci birden fazla iterasyon ve önemli çaba gerektirdi. Ölçülebilir sonuçlar: %43 performans iyileştirmesi, %32 maliyet azaltması ve %95 daha az altyapı hatası.

Ana fayda, daha iyi araçlar, testler ve rollback yetenekleri sayesinde artan deployment güvenidir.

CDK sadece Infrastructure as Code değil - Infrastructure as Actual Code. Gerçek programlama dilleri, gerçek test framework’leri ve gerçek software engineering uygulamaları ile.

Production serverless uygulamaları yönetiyorsanız, bu migration path’ini düşünün. Öğrenme eğrisi dik, ama verimlilik kazanımları dönüştürücü.

Serverless infrastructure’ın geleceğine hoş geldiniz. TypeScript ile yazılıyor, CI/CD’de test ediliyor ve güvenle deploy ediliyor.

Serverless Framework'ten AWS CDK'ya Geçiş Rehberi

Serverless Framework'ten AWS CDK'ya tam geçiş sürecini kapsayan 6 bölümlük kapsamlı rehber. Kurulum, uygulama pattern'leri ve best practice'ler dahil.

İlerleme 6 / 6 yazı

İlgili yazılar

AWS CDK Link Shortener Bölüm 4: Production Deployment ve Optimizasyon

Multi-environment deployment stratejileri, ölçekte performans optimizasyonu, ve maliyet yönetimi. Production deneyimleri ve öğrenilen dersler ile doğru monitoring ve incident response pattern'ları.

aws-cdklambdadynamodb+6
React Native Expo ile Sentry Entegrasyonu: Pratik Hızlı Rehber

React Native Expo uygulamasına Sentry hata izleme entegrasyonu için adım adım rehber. SDK başlatma, Expo Router enstrümantasyonu, session replay, EAS Build ve EAS Update için source map yükleme ve sık karşılaşılan sorunları kapsar.

react-nativeexpomonitoring+2
DynamoDB Rate Limiting: Single Table Design'da Ölçekte Stratejiler

Single Table Design uygulamalarında DynamoDB throttling'i önleme ve yönetme stratejileri. Partition key tasarımı, write sharding, kapasite modları, DAX caching, retry pattern'leri ve yüksek throughput sistemler için CloudWatch monitoring konularını kapsar.

dynamodbawsrate-limiting+5
AWS ile Edge Computing: CloudFront Functions vs Lambda@Edge

Global uygulamalar için AWS edge computing çözümlerini seçme ve uygulama üzerine pratik örnekler ve maliyet optimizasyonu stratejileri içeren kapsamlı teknik rehber.

awscloudfrontlambda+6
LangChain Production'da: Çalışan Patternler ve İşe Yaramayan Anti-Patternler

LangChain uygulamalarını production'a taşırken öğrendiklerim. Başarısızlığa yol açan anti-patternler, başarıyı sağlayan patternler, çalışan kod örnekleri ve maliyet optimizasyon stratejileri.

langchainllmproduction+5