Skip to content
~/sph.sh

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.

Kapsamlı hazırlıklardan sonra, CDK migration son aşamasına ulaştı. Altyapı 47 Lambda fonksiyonu, 3 DynamoDB tablosu ve kapsamlı güvenlik yapılandırmalarını içeriyordu. Tüm testler başarılıydı ve performans ölçümleri %40 iyileşme gösteriyordu.

Kritik soru ortaya çıktı: "Production hataları için rollback planı nedir?"

Bu soru odak noktasını teknik uygulamadan operasyonel hazırlığa kaydırdı. Bu yazı son aşamayı kapsıyor—production trafiğini yöneten, hataları idare eden ve kurumsal gereksinimleri karşılayan bir migration stratejisi geliştirme. Üç farklı yaklaşımı test ettik; her birinin güçlü ve zayıf yönleri production kararları için önemli dersler sağladı.

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ı:

typescript
// lib/stacks/production-blue-green-stack.tsimport { 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 validationimport { 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ı:

typescript
// test/infrastructure/api-stack.test.tsimport { 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

typescript
// test/integration/api.test.tsimport { 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

typescript
// test/load/k6-script.jsimport 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

typescript
// lib/constructs/deployment/safe-deployment.tsexport 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.tsexport 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

typescript
// lib/constructs/performance/optimized-function.tsexport 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

typescript
// lib/constructs/performance/cached-api.tsexport 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

typescript
// lib/stacks/monitoring-stack.tsexport 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

typescript
// lib/constructs/observability/tracing.tsexport 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.tsimport { 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ı

typescript
// Hardcoded isimlerden kaçın// Kötüconst table = new Table(this, 'Table', {  tableName: 'users-table', // Varsa çakışır});
// İyiconst table = new Table(this, 'Table', {  tableName: `${props.serviceName}-${props.stage}-users`,});

2. State Management

typescript
// Stateful ve stateless kaynakları ayırconst app = new App();
// Stateful kaynaklar ayrı stack'teconst dataStack = new DataStack(app, 'DataStack', {  terminationProtection: true,});
// Stateless kaynaklar serbestçe güncellenebilirconst apiStack = new ApiStack(app, 'ApiStack', {  tables: dataStack.tables,});

3. Environment Variable Migration

typescript
// Serverless variable'larını CDK'ya maplaconst 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.

İlerleme6/6 yazı tamamlandı

İlgili Yazılar