AWS Lambda Katmanları (Layers) ile Bağımlılık Yönetimi
Serverless dünyasında en sık karşılaşılan problemlerden biri şu: her Lambda fonksiyonunu ayrı ayrı paketleyince aynı bağımlılıkları defalarca yüklüyorsun, deployment paketleri şişiyor, güncelleme yapmak cehenneme dönüyor. İşte tam bu noktada Lambda Layers devreye giriyor ve hayatını ciddi anlamda kolaylaştırıyor.
Lambda Katmanları Nedir ve Neden Önemlidir?
Lambda Layer, fonksiyonlardan bağımsız olarak paketleyip yönetebileceğin bir zip arşividir. İçine kütüphaneleri, runtime’ları, konfigürasyon dosyalarını veya özel araçlarını koyabilirsin. Bir kez oluşturup, yüzlerce Lambda fonksiyonuna ekleyebilirsin.
Şöyle düşün: 20 tane Lambda fonksiyonun var ve hepsi pandas, numpy, boto3 kullanıyor. Normalde her fonksiyonun deployment paketine bu kütüphaneleri ekliyorsun. Tek bir kütüphaneyi güncellemek istediğinde 20 fonksiyonu ayrı ayrı yeniden deploy etmek zorundasın. Layer kullanırsan, kütüphaneyi bir kez güncellersin, tüm fonksiyonlar yeni versiyonu kullanmaya başlar.
Pratik faydaları şöyle sıralayabiliriz:
- Deployment paket boyutunu dramatik şekilde küçültür
- Kod paylaşımını merkezi hale getirir
- Bağımlılık yönetimini sadeleştirir
- Fonksiyon kodunu daha okunabilir tutar
- Ekip içinde standart kütüphane setleri oluşturmanı sağlar
Her fonksiyon maksimum 5 layer kullanabilir. Toplam unzipped boyut 250 MB ile sınırlıdır. Bu limitler aklında olsun.
Layer Dizin Yapısı
Layer’ların çalışması için belirli bir dizin yapısına uymak zorundasın. Lambda runtime’ı bu yapıyı bekliyor ve yanlış yapılandırılmış bir layer hiç çalışmıyor.
Python için:
my-layer/
└── python/
└── lib/
└── python3.11/
└── site-packages/
├── pandas/
├── numpy/
└── ...
Node.js için:
my-layer/
└── nodejs/
└── node_modules/
├── lodash/
├── axios/
└── ...
Ruby için:
my-layer/
└── ruby/
└── gems/
└── 3.2.0/
└── ...
Genel binary veya araçlar için /opt/bin dizinini kullanırsın. Layer zip’i açıldığında /opt altına yerleştirilir. Yani python/lib/python3.11/site-packages içindeki paketler otomatik olarak Python path’ine eklenir.
İlk Layer’ını Oluşturma: Python Örneği
Gerçek bir senaryo üzerinden gidelim. Veri işleyen Lambda fonksiyonların için pandas ve numpy içeren bir layer oluşturalım.
# Çalışma dizini oluştur
mkdir -p ~/layer-build/python/lib/python3.11/site-packages
# Kütüphaneleri doğru dizine yükle
pip3 install pandas numpy
--target ~/layer-build/python/lib/python3.11/site-packages
--python-version 3.11
--only-binary=:all:
--platform manylinux2014_x86_64
# Zip dosyası oluştur
cd ~/layer-build
zip -r ../data-science-layer.zip python/
# Dosya boyutunu kontrol et
ls -lh ../data-science-layer.zip
Burada --platform manylinux2014_x86_64 parametresi kritik. Yerel makinende macOS veya Windows kullanıyorsan, Lambda’nın çalıştığı Linux ortamıyla uyumsuz binary’ler yüklenebilir. Bu parametre Linux için uygun binary’lerin indirilmesini zorlar.
Şimdi bu layer’ı AWS’e yükleyelim:
# AWS CLI ile layer oluştur
aws lambda publish-layer-version
--layer-name "data-science-layer"
--description "Pandas ve Numpy iceren veri analizi layer"
--zip-file fileb://../data-science-layer.zip
--compatible-runtimes python3.11 python3.10
--compatible-architectures x86_64 arm64
# Çıktıdan LayerVersionArn'i kaydet
# Örnek: arn:aws:lambda:eu-west-1:123456789:layer:data-science-layer:1
Layer’ı Fonksiyona Ekleme
Layer oluşturulduktan sonra onu Lambda fonksiyonuna bağlamak gerekiyor.
# Mevcut fonksiyona layer ekle
aws lambda update-function-configuration
--function-name veri-isleme-fonksiyonu
--layers "arn:aws:lambda:eu-west-1:123456789012:layer:data-science-layer:1"
# Birden fazla layer ekliyorsan hepsini listele
aws lambda update-function-configuration
--function-name veri-isleme-fonksiyonu
--layers
"arn:aws:lambda:eu-west-1:123456789012:layer:data-science-layer:1"
"arn:aws:lambda:eu-west-1:123456789012:layer:common-utils-layer:3"
# Layer'ların eklendiğini doğrula
aws lambda get-function-configuration
--function-name veri-isleme-fonksiyonu
--query 'Layers[*].Arn'
--output table
Lambda fonksiyonu artık /opt/python/lib/python3.11/site-packages altındaki kütüphanelere erişebilir. Fonksiyon kodunda direkt import pandas as pd diyebilirsin, hiçbir şey değişmez.
Terraform ile Layer Yönetimi
Production ortamında AWS CLI ile tek tek layer yönetmek sürdürülebilir değil. Terraform kullanıyorsan işte temiz bir yapı:
# Layer için dizin yapısını oluştur ve paketleri yükle
#!/bin/bash
# scripts/build-layer.sh
LAYER_NAME=$1
PYTHON_VERSION=${2:-3.11}
REQUIREMENTS_FILE=${3:-requirements.txt}
echo "Layer build başlıyor: $LAYER_NAME"
# Temiz build ortamı
BUILD_DIR=$(mktemp -d)
LAYER_DIR="$BUILD_DIR/python/lib/python${PYTHON_VERSION}/site-packages"
mkdir -p "$LAYER_DIR"
# Paketleri yükle
pip3 install
-r "$REQUIREMENTS_FILE"
--target "$LAYER_DIR"
--python-version "$PYTHON_VERSION"
--only-binary=:all:
--platform manylinux2014_x86_64
--quiet
# Gereksiz dosyaları temizle (boyut optimizasyonu)
find "$LAYER_DIR" -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null
find "$LAYER_DIR" -type d -name "*.dist-info" -exec rm -rf {} + 2>/dev/null
find "$LAYER_DIR" -type d -name "tests" -exec rm -rf {} + 2>/dev/null
# Zip oluştur
cd "$BUILD_DIR"
zip -r "/tmp/${LAYER_NAME}.zip" python/ -q
echo "Layer hazır: /tmp/${LAYER_NAME}.zip"
echo "Boyut: $(du -sh /tmp/${LAYER_NAME}.zip | cut -f1)"
# Temizlik
rm -rf "$BUILD_DIR"
Bu script’i CI/CD pipeline’ına entegre ederek her deployment’ta otomatik layer build alabilirsin.
Gerçek Dünya Senaryosu: Şirket İçi Utility Layer
Çalıştığın şirkette her Lambda fonksiyonunun ihtiyaç duyduğu ortak araçlar var diyelim: logging formatlaması, Secrets Manager’dan konfigürasyon çekme, hata yönetimi. Bunları her fonksiyona kopyalamak yerine bir utility layer oluşturursun.
Önce utility paketini hazırlayalım:
# Utility modülü yapısı
mkdir -p company-utils/python
cat > company-utils/python/company_utils.py << 'EOF'
import json
import logging
import boto3
from datetime import datetime
def setup_logger(function_name, log_level="INFO"):
"""Standart log formatını ayarlar"""
logger = logging.getLogger(function_name)
logger.setLevel(getattr(logging, log_level))
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s | %(name)s | %(levelname)s | %(message)s',
datefmt='%Y-%m-%dT%H:%M:%S'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def get_secret(secret_name, region="eu-west-1"):
"""Secrets Manager'dan değer çeker, sonucu cache'ler"""
client = boto3.client('secretsmanager', region_name=region)
response = client.get_secret_value(SecretId=secret_name)
return json.loads(response['SecretString'])
def build_response(status_code, body, headers=None):
"""API Gateway uyumlu response oluşturur"""
default_headers = {
"Content-Type": "application/json",
"X-Request-Time": datetime.utcnow().isoformat()
}
if headers:
default_headers.update(headers)
return {
"statusCode": status_code,
"headers": default_headers,
"body": json.dumps(body, ensure_ascii=False)
}
EOF
# Layer'ı paketle
cd company-utils
zip -r ../company-utils-layer.zip python/
# Yükle
aws lambda publish-layer-version
--layer-name "company-utils"
--description "Sirket geneli ortak utility fonksiyonlari"
--zip-file fileb://../company-utils-layer.zip
--compatible-runtimes python3.11 python3.10 python3.9
Artık herhangi bir Lambda fonksiyonunda bu modülü şöyle kullanabilirsin:
from company_utils import setup_logger, get_secret, build_response
logger = setup_logger("siparis-isleme")
def lambda_handler(event, context):
logger.info("Siparis isleme basliyor", extra={"order_id": event.get("orderId")})
db_config = get_secret("prod/database/credentials")
# İş mantığı burada
return build_response(200, {"message": "Siparis islendi", "status": "success"})
Layer sayesinde her fonksiyonda aynı logging ve hata yönetimi standardı sağlanıyor. Bir gün setup_logger fonksiyonunu değiştirmen gerekirse, sadece layer’ı güncellersin, 50 fonksiyonu tek tek dolaşmak zorunda kalmazsın.
Layer Versiyonlama ve Güncelleme Stratejisi
Layer’lar immutable’dır. Bir kez oluşturulunca değiştiremezsin, yeni versiyon yayınlarsın. Bu önemli bir detay çünkü bir fonksiyon her zaman belirli bir layer versiyonunu kullanır.
# Mevcut layer versiyonlarını listele
aws lambda list-layer-versions
--layer-name "data-science-layer"
--query 'LayerVersions[*].{Version:Version,Arn:LayerVersionArn,Created:CreatedDate}'
--output table
# Yeni versiyon yayınla
aws lambda publish-layer-version
--layer-name "data-science-layer"
--description "Pandas 2.1.0, Numpy 1.26.0"
--zip-file fileb://data-science-layer-v2.zip
--compatible-runtimes python3.11
# Fonksiyonu yeni layer versiyonuna güncelle
aws lambda update-function-configuration
--function-name veri-isleme-fonksiyonu
--layers "arn:aws:lambda:eu-west-1:123456789012:layer:data-science-layer:2"
# Eski layer versiyonunu sil (temizlik)
aws lambda delete-layer-version
--layer-name "data-science-layer"
--version-number 1
Dikkat: Fonksiyon hala eski versiyonu kullanıyorken layer’ı silersen fonksiyon çalışmaya devam eder çünkü layer içeriği fonksiyona bağlıdır. Ama yeni bir deployment yaptığında sorun çıkabilir. Temizlik yapmadan önce hangi fonksiyonların hangi layer versiyonunu kullandığını kontrol et.
# Hangi fonksiyonların bu layer'ı kullandığını bul
aws lambda list-functions
--query 'Functions[?Layers != `null`].{Name:FunctionName,Layers:Layers[*].Arn}'
--output json |
python3 -c "
import json, sys
data = json.load(sys.stdin)
layer_arn = 'arn:aws:lambda:eu-west-1:123456789012:layer:data-science-layer:1'
for f in data:
if f['Layers'] and any(layer_arn in l for l in f['Layers']):
print(f['Name'])
"
Container Image ile Layer Karşılaştırması
Lambda’yı container image olarak da deploy edebilirsin ve o zaman layer kullanmak zorunda değilsin. Peki hangisi daha iyi?
Container image kullanman gereken durumlar:
- 250 MB’den büyük bağımlılıkların var
- Machine learning modelleri gibi çok büyük dosyalar taşıyorsun
- Özel runtime veya sistem kütüphanelerine ihtiyaç var
- Docker workflow’una zaten entegre bir sürecin var
Layer kullanman gereken durumlar:
- Bağımlılıklar 250 MB altında kalıyor
- Kod paylaşımı ve merkezi yönetim önceliğin
- Hızlı deployment istiyorsun
- Birden fazla fonksiyon aynı kütüphaneleri kullanıyor
Her ikisini birlikte de kullanabilirsin, ama genellikle bir yaklaşımı seçmek daha temiz bir mimari ortaya çıkarır.
AWS SAM ile Layer Tanımlama
SAM kullananlar için template.yaml içinde layer tanımlamak çok daha okunabilir bir yapı sağlar:
# template.yaml örneği
# sam build && sam deploy komutuyla deploy edilir
# Önce SAM build ile layer'ı hazırla
sam build
# Sonra deploy et
sam deploy
--stack-name my-serverless-app
--s3-bucket my-deployment-bucket
--capabilities CAPABILITY_IAM
--parameter-overrides
Environment=production
LayerVersion=1
# Layer değişikliklerini test et
sam local invoke VeriIslemeFunction
--event events/test-event.json
--env-vars env.json
SAM ile geliştirirken sam local komutu layer’ları lokalde de simüle eder. Bu özellikle büyük ekiplerde standartlaşmayı kolaylaştırır.
Boyut Optimizasyonu Teknikleri
Layer boyutu kritik. 250 MB limitine yaklaşıyorsan şu teknikleri dene:
# Gereksiz dosyaları temizle
cd layer-build
# Test dosyalarını kaldır
find python/ -name "test_*.py" -delete
find python/ -name "*_test.py" -delete
find python/ -type d -name "tests" -exec rm -rf {} + 2>/dev/null
# Dokümantasyon kaldır
find python/ -name "*.md" -delete
find python/ -name "*.rst" -delete
find python/ -name "*.txt" -delete 2>/dev/null
# __pycache__ temizle
find python/ -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null
find python/ -name "*.pyc" -delete
# .dist-info dizinlerini kaldır (pip metadata, Lambda'da gereksiz)
find python/ -type d -name "*.dist-info" -exec rm -rf {} + 2>/dev/null
find python/ -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null
# Numpy için özel optimizasyon (test ve doc dosyaları büyük yer tutar)
find python/ -path "*/numpy/core/tests" -exec rm -rf {} + 2>/dev/null
# Boyutu karşılaştır
echo "Temizlik öncesi:"
du -sh python/
zip -r optimized-layer.zip python/ -q
echo "Zip boyutu: $(du -sh optimized-layer.zip | cut -f1)"
Bu temizlik işlemleriyle genellikle %30-40 arası boyut düşüşü sağlayabilirsin. pandas + numpy kombinasyonu normalde 80-100 MB civarında gelir, optimizasyonla 55-65 MB’e düşürebilirsin.
Cross-Account Layer Paylaşımı
Büyük organizasyonlarda farklı AWS hesapları arasında layer paylaşmak isteyebilirsin. Merkezi bir “platform” hesabında layer oluşturup, uygulama hesaplarının bunu kullanmasına izin verebilirsin:
# Layer'ı başka bir AWS hesabıyla paylaş
aws lambda add-layer-version-permission
--layer-name "data-science-layer"
--version-number 2
--statement-id "allow-account-dev"
--action lambda:GetLayerVersion
--principal "111122223333"
# Tüm organizasyonla paylaşmak için (AWS Organizations kullanıyorsan)
aws lambda add-layer-version-permission
--layer-name "company-utils"
--version-number 5
--statement-id "allow-org"
--action lambda:GetLayerVersion
--principal "*"
--organization-id "o-xxxxxxxxxx"
# Mevcut izinleri kontrol et
aws lambda get-layer-version-policy
--layer-name "data-science-layer"
--version-number 2
Diğer hesaptaki geliştirici, sadece full ARN’ı kullanarak bu layer’ı kendi fonksiyonlarına ekleyebilir. Deployment izni gerekmez, sadece lambda:GetLayerVersion yeterli.
Monitoring ve Troubleshooting
Layer sorunlarını debug etmek bazen can sıkıcı olabilir. İşte sık karşılaşılan durumlar ve çözümleri:
“Unable to import module” hatası alıyorsun:
# Lambda loglarına bak
aws logs tail /aws/lambda/veri-isleme-fonksiyonu
--follow
--format short
# Layer içeriğini doğrula
aws lambda get-layer-version
--layer-name "data-science-layer"
--version-number 2
# Zip içeriğini kontrol et
unzip -l data-science-layer.zip | head -30
# Doğru dizin yapısında mı diye kontrol et
unzip -l data-science-layer.zip | grep "site-packages"
# python/lib/python3.11/site-packages/ görmüyorsan yapı yanlış
Layer ekli ama paket import edilemiyor:
En yaygın neden yanlış Python versiyonu. Fonksiyon Python 3.11 kullanıyor ama layer’ı python3.9 için build ettiysen paketler bulunamaz. Layer dizin yapısında python3.11 yazan kısım, fonksiyonun runtime’ıyla eşleşmeli.
Boyut limiti aşıldı:
# Hangi paket en fazla yer kaplıyor?
cd layer-build
du -sh python/lib/python3.11/site-packages/* | sort -rh | head -20
# Gerçekten bu pakete ihtiyacın var mı?
# Bazı paketler (scipy, tensorflow vb.) container image kullanmayı gerektirir
CI/CD Pipeline Entegrasyonu
GitHub Actions ile layer build ve deploy sürecini otomatize etmek production’da şart:
# .github/workflows/deploy-layer.yml içeriği için
# Bu script layer'ın değişip değişmediğini kontrol eder
# ve sadece gerektiğinde yeni versiyon yayınlar
#!/bin/bash
# scripts/check-and-deploy-layer.sh
LAYER_NAME=$1
REQUIREMENTS_FILE=$2
CURRENT_HASH_FILE=".layer-hashes/${LAYER_NAME}.hash"
# Mevcut requirements hash'i hesapla
NEW_HASH=$(sha256sum "$REQUIREMENTS_FILE" | cut -d' ' -f1)
# Önceki hash ile karşılaştır
if [ -f "$CURRENT_HASH_FILE" ]; then
OLD_HASH=$(cat "$CURRENT_HASH_FILE")
if [ "$NEW_HASH" = "$OLD_HASH" ]; then
echo "Layer değişmedi, deploy atlanıyor: $LAYER_NAME"
exit 0
fi
fi
echo "Layer değişti, yeni versiyon oluşturuluyor: $LAYER_NAME"
# Build ve deploy
bash scripts/build-layer.sh "$LAYER_NAME" "3.11" "$REQUIREMENTS_FILE"
LAYER_ARN=$(aws lambda publish-layer-version
--layer-name "$LAYER_NAME"
--zip-file "fileb:///tmp/${LAYER_NAME}.zip"
--compatible-runtimes python3.11
--query 'LayerVersionArn'
--output text)
echo "Yeni layer ARN: $LAYER_ARN"
# Hash'i güncelle
mkdir -p ".layer-hashes"
echo "$NEW_HASH" > "$CURRENT_HASH_FILE"
# ARN'ı SSM Parameter Store'a yaz
# Diğer servisler buradan okuyabilir
aws ssm put-parameter
--name "/layers/${LAYER_NAME}/latest-arn"
--value "$LAYER_ARN"
--type String
--overwrite
echo "Layer deploy tamamlandi"
Bu yaklaşımla requirements değişmediği sürece layer yeniden build edilmez, pipeline süresi kısalır.
Sonuç
Lambda Layer’lar ilk bakışta küçük bir özellik gibi görünse de serverless mimarini olgunlaştırmak için güçlü bir araç. Onlarca Lambda fonksiyonunu yönettiğinde bağımlılık kaosunu önlemek, merkezi utility kodunu dağıtmak ve deployment paket boyutlarını kontrol altında tutmak için vazgeçilmez oluyor.
En iyi pratiklerden özetleyecek olursam: her zaman platform uyumlu binary’ler için --platform manylinux2014_x86_64 parametresini kullan, layer’larını boyut optimizasyonundan geçir, versiyonlama stratejini baştan belirle ve mümkünse CI/CD pipeline’ına entegre et. Cross-account paylaşım özelliğini merkezi kütüphane yönetimi için değerlendirmeye değer, özellikle büyüyen organizasyonlarda bu yaklaşım ekipler arasında ciddi bir standartlaşma sağlıyor.
250 MB limitine takılıyorsan ve paketlerin gerçekten o kadar büyükse, container image’a geçiş doğru karar. Ama büyük çoğunluk için layer yaklaşımı daha hızlı, daha esnek ve yönetimi daha kolay bir çözüm sunuyor.
