Serverless Framework Kurulum ve Kullanımı

Bulut dünyasında “sunucu yönetme” derdi artık geçmişte kaldı dense de abartı olmaz. Serverless mimari, özellikle AWS Lambda, Azure Functions veya Google Cloud Functions gibi servisleri kullanarak sadece kodunuzu yazıp deploy etmenizi sağlıyor. Ama bu servisleri elle yönetmek, IAM rolleri, API Gateway konfigürasyonu, CloudWatch log grupları… hepsini tek tek kurmak ciddi bir efor. İşte tam bu noktada Serverless Framework devreye giriyor. Açık kaynaklı bu araç, tüm bu karmaşıklığı YAML dosyaları üzerinden yönetmenizi sağlıyor ve sizi gereksiz operasyonel yükten kurtarıyor.

Serverless Framework Nedir ve Neden Kullanmalısınız

Serverless Framework, cloud provider bağımsız bir deployment aracıdır. AWS, Azure, GCP, Alibaba Cloud gibi farklı platformlara aynı araçla deploy yapabilirsiniz. Arka planda AWS için CloudFormation stack’leri oluşturur, Azure için ARM template’leri hazırlar. Yani altyapıyı kod olarak tanımlamanızı (IaC) sağlar.

Gerçek dünyada ne işe yarar? Diyelim ki bir e-ticaret firmasında çalışıyorsunuz. Sipariş tamamlandığında fatura PDF’i oluşturan, müşteriye e-posta gönderen ve muhasebe sistemine kayıt düşen üç ayrı Lambda fonksiyonunuz var. Bu fonksiyonları tek tek console üzerinden yönetmek hem hatalara açık hem de tekrarlanabilir değil. Serverless Framework ile tüm bu mimayi bir serverless.yml dosyasına yazıp, sls deploy komutuyla dakikalar içinde production’a alabilirsiniz.

Kurulum Gereksinimleri

Başlamadan önce şunların hazır olması gerekiyor:

  • Node.js (v18 veya üzeri önerilir)
  • npm veya yarn
  • AWS CLI (AWS kullanacaksanız)
  • Geçerli cloud provider credentials
  • Python veya Node.js runtime bilgisi (fonksiyonlarınız için)

Kurulum Adımları

Node.js Kurulumu

Eğer sisteminizde Node.js yoksa önce onu kurmanız gerekiyor. Ubuntu/Debian için:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm --version

CentOS/RHEL için:

sudo dnf install -y nodejs npm
# veya eski sistemlerde
sudo yum install -y nodejs npm

Serverless Framework Kurulumu

Global olarak kurmak en pratik yöntem:

npm install -g serverless
# Kurulumu doğrula
serverless --version
# veya kısa komutla
sls --version

Çıktı olarak şuna benzer bir şey görmelisiniz:

Framework Core: 3.38.0
Plugin: 7.2.0
SDK: 4.5.1

AWS Credentials Konfigürasyonu

AWS kullanacaksanız kimlik bilgilerinizi ayarlamanız şart. En basit yol AWS CLI üzerinden:

aws configure
# AWS Access Key ID: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Default region name: eu-west-1
# Default output format: json

Credentials dosyasını elle de düzenleyebilirsiniz:

cat ~/.aws/credentials
# [default]
# aws_access_key_id = AKIAIOSFODNN7EXAMPLE
# aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Birden fazla profil için
# [production]
# aws_access_key_id = AKIA...
# aws_secret_access_key = ...

Serverless Framework’ü belirli bir AWS profiliyle kullanmak isterseniz:

export AWS_PROFILE=production
sls deploy

İlk Proje: Hello World Lambda

Yeni bir proje oluşturmanın en hızlı yolu template kullanmak:

# Node.js için
sls create --template aws-nodejs --path merhaba-lambda
cd merhaba-lambda

# Python için
sls create --template aws-python3 --path python-lambda

Bu komut size iki dosya oluşturur: handler.js ve serverless.yml. Önce handler dosyasına bakalım:

cat handler.js

Varsayılan içerik şöyle görünür:

'use strict';

module.exports.hello = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: 'Go Serverless v3.0! Your function executed successfully!',
        input: event,
      },
      null,
      2
    ),
  };
};

Şimdi bu dosyayı biraz daha gerçekçi hale getirelim:

'use strict';

module.exports.siparisFaturaOlustur = async (event) => {
  const siparisId = event.pathParameters?.siparisId;
  
  if (!siparisId) {
    return {
      statusCode: 400,
      body: JSON.stringify({ hata: 'Siparis ID gerekli' }),
    };
  }
  
  // Gerçek senaryoda burada DB sorgusu, PDF oluşturma vb. olurdu
  console.log(`Siparis ${siparisId} icin fatura olusturuluyor...`);
  
  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
    },
    body: JSON.stringify({
      mesaj: `Siparis ${siparisId} faturasi basariyla olusturuldu`,
      timestamp: new Date().toISOString(),
    }),
  };
};

serverless.yml Dosyasını Anlamak

Projenin kalbi serverless.yml dosyasıdır. Detaylı bir örnek üzerinden gidelim:

service: eticaret-backend

frameworkVersion: '3'

provider:
  name: aws
  runtime: nodejs20.x
  region: eu-west-1
  stage: ${opt:stage, 'dev'}
  memorySize: 256
  timeout: 30
  
  # Environment variables
  environment:
    DB_HOST: ${ssm:/eticaret/${self:provider.stage}/db-host}
    APP_ENV: ${self:provider.stage}
    LOG_LEVEL: ${env:LOG_LEVEL, 'info'}
  
  # IAM permissions
  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:Query
          Resource:
            - arn:aws:dynamodb:${self:provider.region}:*:table/Siparisler
            - arn:aws:dynamodb:${self:provider.region}:*:table/Siparisler/index/*
        - Effect: Allow
          Action:
            - s3:PutObject
            - s3:GetObject
          Resource: arn:aws:s3:::fatura-bucket-${self:provider.stage}/*
        - Effect: Allow
          Action:
            - ses:SendEmail
          Resource: '*'

functions:
  siparisFatura:
    handler: handler.siparisFaturaOlustur
    description: Siparis tamamlandiginda fatura olusturur
    events:
      - http:
          path: /siparisler/{siparisId}/fatura
          method: get
          cors: true
          authorizer:
            name: jwtDogrulayici
            resultTtlInSeconds: 300
  
  siparisKayit:
    handler: siparisler/handler.kayitOlustur
    memorySize: 512
    timeout: 60
    events:
      - http:
          path: /siparisler
          method: post
          cors: true
  
  jwtDogrulayici:
    handler: auth/handler.dogrula
  
  zamanlanmisGorev:
    handler: raporlar/handler.gunlukRapor
    events:
      - schedule: cron(0 6 * * ? *)  # Her gün sabah 6'da UTC

plugins:
  - serverless-offline
  - serverless-dotenv-plugin

custom:
  serverless-offline:
    httpPort: 3000
    lambdaPort: 3002

resources:
  Resources:
    SiparisDynamoDbTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: Siparisler
        AttributeDefinitions:
          - AttributeName: siparisId
            AttributeType: S
        KeySchema:
          - AttributeName: siparisId
            KeyType: HASH
        BillingMode: PAY_PER_REQUEST

Bu YAML dosyası gerçek bir prodüksiyon senaryosunu yansıtıyor. SSM Parameter Store’dan DB bilgilerini çekiyor, DynamoDB ve S3 için gerekli IAM izinlerini tanımlıyor, JWT tabanlı API authorizer ekliyor ve zamanlanmış görev kuruyoruz.

Yerelde Test: serverless-offline

Production’a deploy etmeden önce yerelde test etmek hayat kurtarır. serverless-offline plugin’i bu işi yapar:

npm install --save-dev serverless-offline

# Yerelde başlat
sls offline start
# veya
sls offline

Çıktı şuna benzer:

Starting Offline at stage dev (eu-west-1)
Offline [http for lambda] listening on http://localhost:3002
Function names exposed for local invocation by aws-sdk:
  * siparisFatura: eticaret-backend-dev-siparisFatura

POST | http://localhost:3000/dev/siparisler
GET  | http://localhost:3000/dev/siparisler/{siparisId}/fatura

Testi yapalım:

# POST isteği
curl -X POST http://localhost:3000/dev/siparisler 
  -H "Content-Type: application/json" 
  -d '{"urunId": "PRD001", "miktar": 2, "musteriId": "MST123"}'

# GET isteği
curl http://localhost:3000/dev/siparisler/SIP001/fatura 
  -H "Authorization: Bearer test-token"

Deployment

Geliştirme Ortamına Deploy

# Default stage (serverless.yml'daki tanıma göre)
sls deploy

# Belirli stage için
sls deploy --stage staging

# Belirli region
sls deploy --stage production --region us-east-1

# Verbose çıktı için
sls deploy --verbose

Deploy sırasında Serverless Framework şunları yapar:

  • Kodunuzu zip’ler
  • S3 bucket oluşturur ve zip’i oraya yükler
  • CloudFormation template oluşturur
  • Stack’i create/update eder
  • Lambda fonksiyonlarını, API Gateway’i, IAM rollerini kurar

Tek Fonksiyon Deploy Etmek

Büyük projelerde tüm stack’i her seferinde deploy etmek yavaş olabilir. Sadece değiştirdiğiniz fonksiyonu deploy edebilirsiniz:

sls deploy function --function siparisFatura
sls deploy function --function siparisFatura --stage production

Bu yöntem çok daha hızlı çünkü CloudFormation stack’ini güncellemeden doğrudan Lambda’yı günceller.

Fonksiyonları Invoke Etmek

Deploy ettikten sonra fonksiyonu direkt CLI üzerinden çalıştırabilirsiniz:

# Basit invoke
sls invoke --function siparisFatura

# Event data ile
sls invoke --function siparisFatura --data '{"pathParameters": {"siparisId": "SIP001"}}'

# Dosyadan event okuma
sls invoke --function siparisFatura --path test-events/siparis-event.json

# Logları da görmek için
sls invoke --function siparisFatura --log

Log Yönetimi

Prodüksiyon ortamında log takibi kritik:

# Son logları getir
sls logs --function siparisFatura

# Canlı log takibi
sls logs --function siparisFatura --tail

# Son 30 dakikanın logları
sls logs --function siparisFatura --startTime 30m

# Belirli stage
sls logs --function siparisFatura --stage production

Environment Değişkenleri ve Secrets Yönetimi

Hassas bilgileri doğrudan YAML’a yazmak büyük hata. AWS SSM Parameter Store kullanın:

# SSM'e secret kaydet
aws ssm put-parameter 
  --name "/eticaret/production/db-password" 
  --value "super-gizli-sifre" 
  --type "SecureString"

aws ssm put-parameter 
  --name "/eticaret/production/jwt-secret" 
  --value "jwt-gizli-anahtar" 
  --type "SecureString"

serverless.yml içinde bu değerlere referans:

provider:
  environment:
    DB_PASSWORD: ${ssm:/eticaret/${self:provider.stage}/db-password}
    JWT_SECRET: ${ssm:/eticaret/${self:provider.stage}/jwt-secret}

.env dosyası kullanmak isterseniz serverless-dotenv-plugin işinizi görür:

npm install --save-dev serverless-dotenv-plugin

.env.dev dosyası:

LOG_LEVEL=debug
CACHE_TTL=300
FEATURE_FLAG_YENI_ODEME=true

Çoklu Ortam Yönetimi

Gerçek projelerde en az üç ortam olur: dev, staging, production. Her birinin farklı konfigürasyonu olabilir:

custom:
  ortamAyarlari:
    dev:
      memorySize: 128
      timeout: 10
      logRetentionInDays: 3
    staging:
      memorySize: 256
      timeout: 30
      logRetentionInDays: 7
    production:
      memorySize: 512
      timeout: 60
      logRetentionInDays: 30

provider:
  memorySize: ${self:custom.ortamAyarlari.${self:provider.stage}.memorySize}
  timeout: ${self:custom.ortamAyarlari.${self:provider.stage}.timeout}

Deploy komutları:

# Dev ortamı
sls deploy --stage dev

# Staging
sls deploy --stage staging

# Production - dikkatli ol!
sls deploy --stage production --aws-profile production-admin

CI/CD Entegrasyonu

GitLab CI örneği ile otomatik deployment:

# .gitlab-ci.yml
stages:
  - test
  - deploy-staging
  - deploy-production

variables:
  NODE_VERSION: "20"

.node_setup: &node_setup
  image: node:${NODE_VERSION}
  before_script:
    - npm ci
    - npm install -g serverless

unit-tests:
  <<: *node_setup
  stage: test
  script:
    - npm test
  only:
    - merge_requests
    - main

deploy-staging:
  <<: *node_setup
  stage: deploy-staging
  script:
    - sls deploy --stage staging --verbose
  environment:
    name: staging
  only:
    - main
  variables:
    AWS_ACCESS_KEY_ID: $STAGING_AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY: $STAGING_AWS_SECRET_ACCESS_KEY
    AWS_DEFAULT_REGION: eu-west-1

deploy-production:
  <<: *node_setup
  stage: deploy-production
  script:
    - sls deploy --stage production --verbose
  environment:
    name: production
  when: manual
  only:
    - main
  variables:
    AWS_ACCESS_KEY_ID: $PROD_AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY: $PROD_AWS_SECRET_ACCESS_KEY
    AWS_DEFAULT_REGION: eu-west-1

Production deployment’ı when: manual ile koruma altına aldık. Yani staging’e otomatik deploy olur ama production için birinin GitLab’dan butona basması gerekir.

Stack Silme

Tüm kaynakları temizlemek için:

# Dev ortamını sil
sls remove --stage dev

# Production'ı silmeden önce iki kere düşün!
sls remove --stage production

Bu komut CloudFormation stack’ini siler ve stack’in oluşturduğu tüm kaynakları (Lambda, API Gateway, IAM rolleri) kaldırır. Ancak DeletionPolicy: Retain olarak işaretlenen kaynaklar (örneğin DynamoDB tablonuz) korunur.

Sık Karşılaşılan Sorunlar

Timeout Hataları

Lambda’nız timeout alıyorsa önce neden aldığını anlayın:

sls logs --function siparisFatura --tail

Logda Task timed out after 30.00 seconds görüyorsanız ya timeout değerini artırın (max 15 dakika) ya da fonksiyonunuzu optimize edin. Uzun süren işlemler için SQS + async pattern düşünün.

Cold Start Sorunu

Node.js Lambda’larda cold start can sıkabilir. Çözüm yolları:

  • Provisioned Concurrency: Belirli sayıda Lambda instance’ını her zaman warm tutar, ama maliyet artar
  • serverless-warmup-plugin: Belirli aralıklarla fonksiyonları ping eder
  • Bundle size küçültme: webpack veya esbuild ile sadece kullandığınız kütüphaneleri dahil edin
npm install --save-dev serverless-esbuild
plugins:
  - serverless-esbuild

custom:
  esbuild:
    bundle: true
    minify: true
    target: node20
    exclude:
      - aws-sdk

IAM Yetki Hataları

Deploy sırasında AccessDenied hatası alırsanız, deployment yapan IAM kullanıcısının yeterli yetkisi yok demektir. En azından şu servislere yetki gerekir:

  • CloudFormation (tam yetki)
  • Lambda (tam yetki)
  • API Gateway (tam yetki)
  • IAM (rol oluşturma)
  • S3 (deployment bucket için)
  • CloudWatch Logs

Geliştirme ortamında AdministratorAccess kullanmak pratik olsa da production için minimum yetki prensibi uygulanmalı.

Maliyet Optimizasyonu İpuçları

Serverless maliyet açısından avantajlı ama dikkat edilmezse fatura sürpriz yapabilir:

  • Memory boyutunu doğru ayarlayın: Lambda fiyatı GB-saniye üzerinden hesaplanır. 256MB yeterliyken 1024MB kullanmak maliyeti 4 katına çıkarır
  • Timeout’u gerçekçi tutun: 5 saniyede biten fonksiyon için 5 dakika timeout koymak, yanlışlıkla sonsuz döngüye giren kodun hesabınızı batırmasına yol açar
  • X-Ray tracing’i seçici kullanın: Her fonksiyonda aktif etmek maliyet ekler
  • Log retention’ı ayarlayın: Varsayılan olarak CloudWatch logları sonsuza kadar saklar
provider:
  logRetentionInDays: 14

Sonuç

Serverless Framework, Lambda fonksiyonlarını elle yönetmenin getirdiği karmaşıklığı ciddi ölçüde azaltıyor. Kurulumu basit, öğrenme eğrisi makul ve ekosistem zengin. Özellikle çoklu ortam yönetimi, plugin sistemi ve IaC yaklaşımı, bunu sadece bireysel geliştiriciler için değil kurumsal ekipler için de cazip yapıyor.

Tabi her araç gibi sınırları var. Çok büyük ve karmaşık altyapılar için Terraform veya AWS CDK daha fazla esneklik sunabilir. Ama orta ölçekli serverless projeleri için Serverless Framework hala en pratik seçenek olmaya devam ediyor. Başlangıç olarak küçük bir Lambda projesi kurun, offline plugin ile yerelde test edin, GitLab CI ile pipeline kurun ve production’a deploy edin. Bir kez çalışır hale getirince “nasıl yaşıyordum bunu olmadan” diyeceksiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir