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:
- Bölüm 1: Neden Geçiş Yapalım?
- Bölüm 2: CDK Environment Kurulumu
- Bölüm 3: Lambda Fonksiyonları ve API Gateway Migration
- Bölüm 4: Database ve Environment Management
- Bölüm 5: Authentication, Authorization ve IAM
- Bölüm 6: Migration Stratejileri ve Best Practice’ler (bu yazı)
Üç 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:
- Basit CRUD uygulamaları minimal customization ihtiyaçlarıyla
- Proof-of-concept projeler hızlı prototyping’e ihtiyaç duyan
- TypeScript deneyimi olmayan ekipler ve eğitim için bandwidth olmayan
- Heavy plugin dependency’leri olan uygulamalar CDK’da var olmayan
- 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.
Serideki tüm yazılar
İlgili yazılar
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ı.
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.
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.
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.
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.