İçeriğe atla

Serverless Framework mi AWS CDK mi? Geçiş Yapmalı mısınız? (Bölüm 1)

Serverless Framework'ten AWS CDK'ya geçiş rehberinin ilk bölümü. Neden geçiş yapmalı, temel kavramlar ve ilk adımlar.

Ayhan Sipahi Ayhan Sipahi

Serverless Framework ve AWS CDK, örtüşen sorunları farklı felsefelerle çözer. Serverless Framework, Lambda merkezli bir deploy birimi üzerinde YAML güdümlü, sağlayıcıdan bağımsız bir soyutlamadır; CDK ise CloudFormation üzerinde tip güvenli, AWS-native bir sentez katmanıdır. Serverless Framework ücretli lisans modeline geçtiğinde, olduğun yerde kalmak artık bedelsiz varsayılan olmaktan çıktı ve karşılaştırmayı yeniden yapmak anlamlı hale geldi.

AWS’e zaten bağlanmış ve bir avuçtan fazla fonksiyon çalıştıran bir ekip için varsayılan tercih CDK: tip güvenli cross-stack referanslar, Serverless Framework’ün plugin ile ulaştığı servisler için native construct’lar ve unit test edilebilir altyapı. Bedeli ise daha derin AWS bağımlılığı ve TypeScript öğrenme eğrisi. Tek şikayeti lisans maliyeti olan küçük ve oturmuş bir Lambda + API Gateway uygulaması, bu bedeli genelde geri kazandırmaz.

Bu altı bölümlük seri tüm geçiş sürecini kapsıyor:

Lisans Maliyeti ve Operasyonel Maliyet#

Lisans ücreti görünen maliyettir. Kararı belirleyen ise çoğu zaman altındaki operasyonel maliyetlerdir. Ekipleri CDK’ya yönlendiren iki katman da burada:

Doğrudan Maliyetler#

Serverless Framework’ün Pro katmanı deployment başına ücretlendirir ve ekip büyüdükçe bu maliyet de büyür; daha fazla özellik ücretli seviyelerin arkasına taşınır. CDK’da ayrı bir lisans ücreti yok: AWS CLI’nın parçası olarak gelir, infrastructure’ı standart uygulama kodu gibi ele alır ve AWS servislerini native destekler.

Gizli Operasyonel Maliyetler#

Her iki araç da faturada görünmeyen sürekli maliyetler taşır. YAML syntax’ı büyüdükçe bakımı zorlaşır, üçüncü taraf plugin’ler kendi uyumluluk sorunlarını getirir, cross-service referanslar tip güvenli objeler yerine string’e dayanır, debugging ise compile-time yerine runtime’da ortaya çıkar.

Pratikte Compile-Time Güvenliği#

Günlük çalışmada öne çıkan farklar kararı şekillendirir:

Konfigürasyon Hataları ve Plugin Yükü#

YAML’da konfigürasyon typo’ları production’a kadar ulaşabilir. TypeScript bunları compile time’da durdurur. Serverless Framework, webhook secret’ını doğrudan environment’tan okur:

# serverless.yml
provider:
  environment:
    STRIPE_API_KEY: ${env:STRIPE_API_KEY}
    STRIPE_WEBHOOK_SECRET: ${env:STRIPE_WEBHOOK_SECRET}

CDK, STRIPE_WEBHOOK_SECRET’ı application kodunda okur ve eksikse deploy’dan önce hata fırlatır:

// Environment variable'lar compile time'da validate ediliyor
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
if (!webhookSecret) {
  throw new Error('STRIPE_WEBHOOK_SECRET environment variable gerekli');
}

Gelişmiş özellikler Serverless Framework’ü community plugin’lere yöneltir; her plugin, Node.js güncellemeleri sırasında takip edilmesi gereken kendi uyumluluk yükünü getirir:

plugins:
  - serverless-webpack
  - serverless-offline
  - serverless-step-functions

custom:
  webpack:
    webpackConfig: webpack.config.js

CDK tarafında bu yüke gerek yok:

// Native bundling ve servis entegrasyonu
const bundling = {
  target: 'node20',
  minify: true,
  sourceMap: true,
};

Cross-Stack Tip Güvenliği#

CDK, CloudFormation export’larının yerine tip güvenli obje referansları koyar. Bağımlılıklar açık ve tip kontrollü kalır, bu da refactoring’i daha güvenli kılar:

// Compile-time validation ile doğrudan obje referansları
const authStack = new AuthStack(this, 'AuthStack', {
  userTable: databaseStack.userTable, // TypeScript bunun var olduğunu garanti eder
});

Serverless Framework’te bağımlılığı CloudFormation export’ları ve string interpolation kurar:

# auth-service/serverless.yml
provider:
  environment:
    USER_TABLE_ARN: ${cf:database-stack-${opt:stage}.UserTableArn}

Tek Fonksiyonun Ötesinde Ölçeklenme#

İki yaklaşım arasındaki fark, uygulama tek bir endpoint’in ötesine büyüdükçe açılır. Bir createUser route bu farkı pratikte gösterir. Serverless Framework onu YAML’da tanımlar:

# serverless.yml
provider:
  name: aws
  runtime: nodejs20.x
  environment:
    TABLE_NAME: ${self:service}-${opt:stage}-users

functions:
  createUser:
    handler: src/handlers/users.create
    events:
      - http:
          path: users
          method: post
          cors: true

CDK, fonksiyonu ve route’unu kodda doğrudan bağlar:

// lib/api-stack.ts
import { RestApi, LambdaIntegration } from 'aws-cdk-lib/aws-apigateway';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';

const createUserFn = new NodejsFunction(this, 'CreateUserFunction', {
  entry: 'src/handlers/users.ts',
  handler: 'create',
  environment: {
    TABLE_NAME: userTable.tableName,
  },
});

// Tip güvenli entegrasyon
const api = new RestApi(this, 'UserApi');
api.root.addResource('users').addMethod('POST',
  new LambdaIntegration(createUserFn)
);

Plugin Olmadan Step Functions ve AppSync#

CDK, ekstra bir bağımlılık olmadan Step Functions, AppSync ve CloudWatch alarmlarının üçüne de kendi construct’ları üzerinden ulaşır:

import { DefinitionBody, StateMachine } from 'aws-cdk-lib/aws-stepfunctions';
import { LambdaInvoke } from 'aws-cdk-lib/aws-stepfunctions-tasks';
import { Definition, GraphqlApi } from 'aws-cdk-lib/aws-appsync';
import { Alarm } from 'aws-cdk-lib/aws-cloudwatch';

// Plugin olmadan doğrudan servis entegrasyonu
const workflow = new StateMachine(this, 'UserWorkflow', {
  definitionBody: DefinitionBody.fromChainable(
    new LambdaInvoke(this, 'ProcessUser', {
      lambdaFunction: processUserFn,
    })
  ),
});

const api = new GraphqlApi(this, 'UserGraphQL', {
  name: 'user-api',
  definition: Definition.fromFile('schema.graphql'),
});

new Alarm(this, 'ProcessUserErrors', {
  metric: processUserFn.metricErrors(),
  threshold: 1,
  evaluationPeriods: 1,
});

Serverless Framework’te bunların her biri ayrı bir plugin gerektirir:

plugins:
  - serverless-step-functions
  - serverless-appsync-plugin
  - serverless-plugin-aws-alerts

custom:
  alerts:
    stages:
      - production
    topics:
      alarm:
        topic: ${self:service}-${opt:stage}-alerts

Yeniden Kullanılabilir API Construct’ı#

API construct’ını yeniden kullanılabilir bir class içinde sarmalamak, CDK’ya gerçek object-oriented infrastructure kazandırır:

// lib/constructs/serverless-api.ts
export class ServerlessApi extends Construct {
  public readonly api: RestApi;
  public readonly functions: Map<string, NodejsFunction>;

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

    // Kapsüllenmiş, yeniden kullanılabilir infrastructure kalıpları
    this.api = new RestApi(this, 'Api', {
      restApiName: props.apiName,
      deployOptions: this.createDeployOptions(props.stage),
    });

    this.functions = this.createFunctions(props.routes);
    this.setupRoutes(props.routes);
    this.setupAlarms(props.monitoring);
  }
}

// Birden fazla stack'te kullanım
new ServerlessApi(this, 'UserApi', {
  apiName: 'users',
  routes: userRoutes,
  monitoring: productionMonitoring,
});

Serverless Framework bunu include’lar ve paylaşılan variable dosyalarıyla yaklaşık olarak sağlar:

# serverless.yml
custom:
  userTableConfig: ${file(./config/tables.yml):userTable}

resources:
  Resources:
    UserTable: ${self:custom.userTableConfig}

Stack İçin Unit Test Yazmak#

Serverless Framework’te test etmek genellikle şunları içerir:

  • Framework davranışını mocklama
  • Deploy edilmiş kaynakları test etme
  • Sınırlı unit test seçenekleri

Synthesize edilmiş template’in kendisine karşı, CDK testleri doğrudan çalışır:

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

const template = Template.fromStack(stack);

test('API Gateway CORS etkin', () => {
  template.hasResourceProperties('AWS::ApiGateway::Method', {
    Integration: {
      IntegrationResponses: [{
        ResponseParameters: {
          'method.response.header.Access-Control-Allow-Origin': "'*'",
        },
      }],
    },
  });
});

test("Lambda doğru environment variable'lara sahip", () => {
  template.hasResourceProperties('AWS::Lambda::Function', {
    Environment: {
      Variables: {
        TABLE_NAME: { Ref: Match.anyValue() },
        STAGE: 'production',
      },
    },
  });
});

Her Aracın Üstün Olduğu Durumlar#

CDK’nın Öne Çıktığı Noktalar#

CDK, AWS yüzeyi karmaşıklaştıkça öne çıkar: Step Functions, EventBridge ve AppSync entegrasyonları; ekipler arası yeniden kullanılabilir kalması gereken infrastructure kalıpları; custom CloudFormation kaynakları üzerinde ince taneli kontrol; stack boyunca TypeScript typing; infrastructure’ın kendisi için unit ve entegrasyon testleri; ve birden fazla ekip aynı koda dokunduğunda açık bağımlılıklar ve interface’ler.

Serverless Framework birkaç durumda hâlâ kazanıyor:

  • Basit bir Lambda + API Gateway CRUD API’si
  • Mevcut plugin ecosystem’ine ağır bağımlılığı olan bir ekip
  • TypeScript yerine YAML’ı tercih eden geliştiriciler
  • Hızlı prototipler
  • Infrastructure karmaşıklığının önem taşımayacağı kadar küçük uygulamalar

Geçişin Kapsamını Belirleme#

Geçişten önce işin boyutunu mevcut kurulumuna göre ölç. Eforu belirleyen beş sinyal var:

SinyalDüşük eforYüksek efor
Fonksiyon sayısıTek serviste onlarca fonksiyonBirkaç serviste yüzlerce fonksiyon
Custom kaynaklarYok veya düz CloudFormationCustom resource ve macro’lar
Plugin’lerSadece lokal geliştirme ve bundler plugin’leriCDK karşılığı olmayan plugin’ler
OrtamlarBir veya iki stageGeliştirici ve bölge başına stage
CI/CDTek bir deploy pipeline’ıServerless Framework CLI çıktısına bağlı pipeline

Teknik Değerlendirme#

  • Lambda fonksiyonları ve servislerin sayısı
  • Custom kaynaklar ve CloudFormation kullanımı
  • Cross-service bağımlılıkları
  • Plugin bağımlılıkları ve bakım yükü

Ekip ve Geçiş Hazırlığı#

Beceri, infrastructure boyutu kadar önemlidir: mevcut TypeScript deneyim seviyesi, infrastructure as code’a aşinalık, gerçekte ne kadar öğrenme zamanı olduğu ve deklaratif YAML yerine programatik infrastructure ile kurulan rahatlık. Geçiş planının kendisi de ayrı bir karar: kademeli geçiş mi tam geçiş mi, rollback prosedürleri ve test etme, geçiş sırasında paralel infrastructure ve ekip eğitimi ile bilgi transferi için ayrılan zaman.

Sonraki Bölüm#

Geçiş kararını verdikten sonra asıl iş başlıyor: güvenli ve kademeli geçişi destekleyen bir CDK proje yapısı kurmak.

Bölüm 2 bu kurulum adımlarını ele alıyor: proje mimarisi kalıpları, geliştirme iş akışları ve geçişi yönetilebilir kılan environment konfigürasyonu.

Kaynaklar#

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 1/6 yazı tamamlandı

İlgili yazılar