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.
