İçeriğe atla

Lambda Layer Versiyon Yönetimi: Çok Ortamlı Deployment Stratejileri

Dev, staging ve production ortamlarında Lambda Layer versiyonlarını AWS CDK ile yönetmek için pratik yaklaşımlar: otomatik pipeline ve rollback dahil.

Ayhan Sipahi Ayhan Sipahi

AWS Lambda bir layer’a otomatik artan bir tam sayı veriyor, üstüne hiçbir şey vermiyor. Semantic versiyon yok, ortamlar arasında terfi yolu yok, hangi fonksiyonun hangi build’i çalıştırdığına dair kayıt yok. Takımlar bu boşluğu ellerinin altındaki en kolay yöntemle kapatıyor; dev, staging ve production’ın birbirinden farklı üç layer versiyonunda kalması ve hiçbirinin bir değişikliğe bağlanamaması da böyle oluyor.

Başlangıç için doğru varsayılan bir version manifest: repoda duran, her ortam için explicit bir layer ARN’i sabitleyen, commit ile terfi ettirilen ve revert ile geri alınan bir YAML dosyası. Git üzerinde tam bir audit trail veriyor, deploy sırasında hiçbir lookup gerektirmiyor. Elle düzenlenen bir dosyanın yetmediği durumlar için diğer üç strateji devreye giriyor.

Layer Versiyonları Farklılaştığında#

Explicit bir strateji olmadan ortamlar sessizce birbirinden uzaklaşıyor. Dev en yeni dependency’lerle Layer v5 çalıştırıyor, staging iki release önce aldığı v3’te kalmış, production ise kimsenin ne zaman deploy ettiğini hatırlamadığı bir v4’te duruyor. Belirli bir security patch’inin hangi versiyonda olduğunu bulmak tahmin işine dönüyor.

Bedeli genellikle rutin bir update sırasında ortaya çıkıyor. Monitoring layer’ındaki bir bug fix dev’de test ediliyor, sonra production’a terfi ediyor ve dakikalar içinde fonksiyonlar hata vermeye başlıyor; çünkü layer, bazı fonksiyonların güvendiği bir transitive dependency’nin versiyonunu değiştirmiş. Hangi fonksiyonların etkileneceğini deployment sırasında gösteren hiçbir şey yok.

Serverless kod tabanlarında bu pattern, layer versiyonlaması deployment sözleşmesinin parçası olmak yerine sonradan düşünülen bir ayrıntı olarak kaldığı her yerde tekrarlanıyor.

Çok Ortamlı Versiyon Kontrolü#

İhtiyacımız olan şey:

  • Versiyonları explicit olarak takip etmek - dev, staging ve production ortamlarında
  • Kazara update’leri önlemek - dev deneyleri production’ı bozmamalı
  • Kontrollü terfi sağlamak - dev’de test et, staging’de doğrula, production’a terfi ettir
  • Rollback desteği - bir şeyler bozulduğunda, hızlıca bilinen iyi bir versiyona dön
  • Audit trail’i korumak - kim, ne zaman, hangi versiyonu değiştirdi ve neden
  • Deployment’ları otomatikleştirmek - layer update’lerini mevcut CI/CD pipeline’larına entegre et
  • Cross-account paylaşımı yönetmek - multi-account AWS mimarileri çalıştıran takımlar için

Kısıt şu: AWS Lambda Layer’ların built-in semantic versiyonlaması yok. Auto-increment olan numeric versiyonlar var, ama versiyonları ortamlar arasında yönetmenin veya nerede ne deploy edildiğini takip etmenin native bir yolu yok.

Dört Versiyon Stratejisi#

Birkaç yaklaşımla çalıştıktan sonra, versiyon yönetimi probleminin farklı yönlerini çözen dört strateji:

Strateji A: İsimlendirme ile Semantic Versiyonlama#

En basit yaklaşım - versiyon bilgisini doğrudan layer isminde kodla:

import { LayerVersion, Code, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Stack } from 'aws-cdk-lib';

const dataProcessingLayer = new LayerVersion(this, 'DataProcessingLayer', {
  code: Code.fromAsset('layers/data-processing'),
  compatibleRuntimes: [Runtime.NODEJS_20_X],
  layerVersionName: `data-processing-v2-3-1`, // İsimde versiyon
  description: `Data Processing Layer v2.3.1 - ${new Date().toISOString()}`
});

Güçlü yanı: Hızlı implement edilir, versiyon AWS console’da hemen görünür, ekstra infrastructure gerekmez.

Zayıf yanı: Versiyonları ortamlar arası terfi ettirirken hala manuel ARN update gerekir. Otomatik promotion path yok. Versiyon geçmişi sorgulanamaz.

Strateji B: Ortama Özgü Layer Stack’leri#

Her ortam için pinlenmiş versiyonlarla ayrı layer stack’leri deploy et:

import { Stack, StackProps } from 'aws-cdk-lib';
import { LayerVersion, Code, Runtime, ILayerVersion } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

interface LayerStackProps extends StackProps {
  environment: 'dev' | 'staging' | 'prod';
}

export class LayerStack extends Stack {
  public readonly layers: Record<string, ILayerVersion>;

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

    const { environment } = props;

    // Ortam başına specific versiyonları pinle
    const versionConfig = {
      dev: '3.0.0-beta.2',
      staging: '2.5.1',
      prod: '2.5.0'
    };

    this.layers = {
      monitoring: new LayerVersion(this, 'MonitoringLayer', {
        code: Code.fromAsset(`layers/monitoring`),
        layerVersionName: `monitoring-${environment}-${versionConfig[environment]}`,
        description: `Monitoring Layer ${versionConfig[environment]} for ${environment}`
      })
    };
  }
}

Güçlü yanı: Net ortam sınırları, her ortam bağımsız versiyonlanır, neyin nerede deploy edildiği kolay görünür.

Zayıf yanı: Versiyon konfigürasyonu hala kod içinde. Versiyonları terfi ettirmek kod değişikliği ve redeployment gerektirir. Birkaç layer’dan fazlası için scale etmez.

Strateji C: ARN Yönetimi için SSM Parameter Store#

Layer ARN’lerini SSM Parameter Store’da sakla ve hardcode etmek yerine parametre adıyla çöz:

import { SSM } from '@aws-sdk/client-ssm';
import { StringParameter, IStringParameter } from 'aws-cdk-lib/aws-ssm';
import { LayerVersion, ILayerVersion } from 'aws-cdk-lib/aws-lambda';

// Layer versiyonlarını SSM'de yönetmek için utility class
export class LayerVersionManager {
  static async publishLayer(
    layerName: string,
    version: string,
    environment: string,
    layerArn: string
  ): Promise<void> {
    const parameterName = `/lambda-layers/${environment}/${layerName}/arn`;

    await new SSM().putParameter({
      Name: parameterName,
      Value: layerArn,
      Type: 'String',
      Description: `${layerName} v${version} for ${environment}`,
      Tags: [
        { Key: 'Version', Value: version },
        { Key: 'Environment', Value: environment },
        { Key: 'LayerName', Value: layerName }
      ],
      Overwrite: true
    });
  }

  static async getLayerArn(
    layerName: string,
    environment: string
  ): Promise<string> {
    const param = await new SSM().getParameter({
      Name: `/lambda-layers/${environment}/${layerName}/arn`
    });
    return param.Parameter!.Value!;
  }
}

// CDK stack'te kullanım
const monitoringLayerArn = StringParameter.valueFromLookup(
  this,
  `/lambda-layers/${environment}/monitoring/arn`
);

const monitoringLayer = LayerVersion.fromLayerVersionArn(
  this,
  'MonitoringLayer',
  monitoringLayerArn
);

Güçlü yanı: Merkezi versiyon yönetimi, mevcut versiyonları sorgulamak kolay, otomatik promotion workflow’larını destekler, parameter geçmişi audit trail sağlar.

Zayıf yanı: Infrastructure’a SSM dependency ekler, hafif komplexite artışı, initial parameter setup gerekir.

Strateji D: Version Manifest (Önerilen)#

Ortam başına layer ARN’lerini takip eden, Git’e commit edilen bir YAML dosyası tut:

# config/layer-versions.yml
layers:
  monitoring:
    dev: "arn:aws:lambda:us-east-1:123456789012:layer:monitoring-dev:15"
    staging: "arn:aws:lambda:us-east-1:123456789012:layer:monitoring-staging:12"
    prod: "arn:aws:lambda:us-east-1:123456789012:layer:monitoring-prod:10"

  data-processing:
    dev: "arn:aws:lambda:us-east-1:123456789012:layer:data-processing-dev:8"
    staging: "arn:aws:lambda:us-east-1:123456789012:layer:data-processing-staging:7"
    prod: "arn:aws:lambda:us-east-1:123456789012:layer:data-processing-prod:6"

Manifest kullanan CDK implementasyonu:

import * as fs from 'fs';
import * as yaml from 'js-yaml';
import { Stack, StackProps } from 'aws-cdk-lib';
import { Function, Code, Runtime, LayerVersion } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

interface LayerVersionManifest {
  layers: Record<string, Record<string, string>>;
}

interface FunctionStackProps extends StackProps {
  environment: 'dev' | 'staging' | 'prod';
}

export class FunctionStack extends Stack {
  constructor(scope: Construct, id: string, props: FunctionStackProps) {
    super(scope, id, props);

    const manifest = yaml.load(
      fs.readFileSync('config/layer-versions.yml', 'utf8')
    ) as LayerVersionManifest;

    const monitoringLayer = LayerVersion.fromLayerVersionArn(
      this,
      'MonitoringLayer',
      manifest.layers.monitoring[props.environment]
    );

    const dataProcessingLayer = LayerVersion.fromLayerVersionArn(
      this,
      'DataProcessingLayer',
      manifest.layers['data-processing'][props.environment]
    );

    new Function(this, 'DataProcessor', {
      runtime: Runtime.NODEJS_20_X,
      handler: 'index.handler',
      code: Code.fromAsset('lambda/data-processor'),
      layers: [monitoringLayer, dataProcessingLayer]
    });
  }
}

Güçlü yanı: Git-tracked versiyonlar tam audit trail sağlar. Versiyonları terfi ettirmek explicit manifest update ve commit gerektirir. Sıfır runtime dependency veya lookup. Git revert ile basit rollback. GitOps workflow’larıyla mükemmel çalışır.

Zayıf yanı: Manifest’i güncel tutmak için disiplin gerekir. Manifest update’leri layer deployment’larıyla senkronize edilmeli.

Otomatik Deployment Pipeline#

Layer deployment’larını version manifest’i koruyarak CI/CD’ye nasıl entegre edeceğin:

# .github/workflows/layer-deployment.yml
name: Lambda Layer Build & Deploy

on:
  push:
    paths:
      - 'layers/**'
    branches:
      - develop
      - staging
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Determine environment
        id: env
        run: |
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            echo "environment=prod" >> $GITHUB_OUTPUT
          elif [ "${{ github.ref }}" == "refs/heads/staging" ]; then
            echo "environment=staging" >> $GITHUB_OUTPUT
          else
            echo "environment=dev" >> $GITHUB_OUTPUT
          fi

      - name: Install layer dependencies
        run: |
          cd layers/monitoring
          npm ci --production
          cd ../data-processing
          npm ci --production

      - name: Run tests
        run: |
          npm test

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: us-east-1
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubActionsRole

      - name: Deploy layer stack
        env:
          ENVIRONMENT: ${{ steps.env.outputs.environment }}
        run: |
          npx cdk deploy LayerStack-$ENVIRONMENT \
            --context environment=$ENVIRONMENT \
            --require-approval never \
            --outputs-file layer-outputs.json

      - name: Update version manifest
        run: |
          # CDK output'larından layer ARN'lerini çıkar
          MONITORING_ARN=$(jq -r '.["LayerStack-'$ENVIRONMENT'"].MonitoringLayerArn' layer-outputs.json)
          DATA_ARN=$(jq -r '.["LayerStack-'$ENVIRONMENT'"].DataProcessingLayerArn' layer-outputs.json)

          # yq kullanarak manifest'i güncelle
          yq eval ".layers.monitoring.$ENVIRONMENT = \"$MONITORING_ARN\"" -i config/layer-versions.yml
          yq eval ".layers.data-processing.$ENVIRONMENT = \"$DATA_ARN\"" -i config/layer-versions.yml

      - name: Commit version manifest
        if: steps.env.outputs.environment != 'dev'
        run: |
          git config user.name "GitHub Actions Bot"
          git config user.email "actions@github.com"
          git add config/layer-versions.yml
          git commit -m "chore: update layer versions for ${{ steps.env.outputs.environment }}"
          git push

Bu pipeline otomatik olarak:

  • Branch’e göre ortamı tespit eder
  • Layer’ları build eder ve test eder
  • Layer stack’ini AWS’e deploy eder
  • Version manifest’i yeni ARN’lerle günceller
  • Manifest değişikliklerini commit eder (staging/prod için)

Cross-Account Layer Paylaşımı#

Multi-account mimariler için layer paylaşım pattern’i:

import { Stack, StackProps, CfnOutput } from 'aws-cdk-lib';
import { Function, LayerVersion, Code, Runtime } from 'aws-cdk-lib/aws-lambda';
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
import { Construct } from 'constructs';

// Tooling account: Layer oluştur ve paylaş
export class SharedLayerStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const sharedLayer = new LayerVersion(this, 'SharedUtilsLayer', {
      code: Code.fromAsset('layers/shared-utils'),
      compatibleRuntimes: [Runtime.NODEJS_20_X],
      layerVersionName: 'shared-utils-v1-0-0'
    });

    // Workload account'lara erişim ver
    const workloadAccounts = ['111111111111', '222222222222', '333333333333'];

    workloadAccounts.forEach(accountId => {
      sharedLayer.addPermission(`AccessFrom${accountId}`, {
        accountId,
        organizationId: 'o-xxxxxxxxxx' // Opsiyonel: organization'a kısıtla
      });
    });

    // Cross-account referans için ARN'i export et
    new CfnOutput(this, 'SharedLayerArn', {
      value: sharedLayer.layerVersionArn,
      exportName: 'SharedUtilsLayerV1-0-0-Arn'
    });

    // Dokümantasyon için SSM'de sakla
    new StringParameter(this, 'SharedLayerArnParam', {
      parameterName: '/shared-layers/utils/v1-0-0/arn',
      stringValue: sharedLayer.layerVersionArn,
      description: 'Shared Utils Layer v1.0.0 ARN for cross-account access'
    });
  }
}

// Workload account: Shared layer kullan
export class WorkloadStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // Tooling account'tan layer'a referans
    const sharedLayerArn = 'arn:aws:lambda:us-east-1:999999999999:layer:shared-utils-v1-0-0:1';

    const sharedLayer = LayerVersion.fromLayerVersionArn(
      this,
      'SharedUtilsLayer',
      sharedLayerArn
    );

    new Function(this, 'MyFunction', {
      runtime: Runtime.NODEJS_20_X,
      handler: 'index.handler',
      code: Code.fromAsset('lambda/my-function'),
      layers: [sharedLayer]
    });
  }
}

Önemli detay: Cross-account SSM parameter lookup’lar çalışmaz. ARN’i version manifest’inde sakla veya aynı account içinde CloudFormation export’ları kullan.

Rollback Implementasyonu#

Bir layer update sorun çıkardığında, hızlı rollback gerekir:

import { SSM } from '@aws-sdk/client-ssm';
import { CloudFormation } from '@aws-sdk/client-cloudformation';

interface RollbackConfig {
  environment: 'dev' | 'staging' | 'prod';
  layerName: string;
  targetVersion?: string; // Opsiyonel: versiyon belirt, yoksa önceki
}

async function rollbackLayer(config: RollbackConfig): Promise<void> {
  const ssm = new SSM({ region: 'us-east-1' });
  const cfn = new CloudFormation({ region: 'us-east-1' });

  const parameterName = `/lambda-layers/${config.environment}/${config.layerName}/arn`;

  // Parameter geçmişini al
  const history = await ssm.getParameterHistory({
    Name: parameterName,
    MaxResults: 10
  });

  if (!history.Parameters || history.Parameters.length < 2) {
    throw new Error('Rollback için önceki versiyon yok');
  }

  // Target versiyonu belirle
  let targetParameter;
  if (config.targetVersion) {
    targetParameter = history.Parameters.find(p =>
      p.Description?.includes(config.targetVersion!)
    );
  } else {
    // Önceki versiyona roll back et
    targetParameter = history.Parameters[1];
  }

  if (!targetParameter) {
    throw new Error('Target versiyon geçmişte bulunamadı');
  }

  console.log(`${config.layerName} rollback yapılıyor: ${config.environment}`);
  console.log(`Mevcut: ${history.Parameters[0].Value}`);
  console.log(`Hedef: ${targetParameter.Value}`);

  // Parameter'ı güncelle
  await ssm.putParameter({
    Name: parameterName,
    Value: targetParameter.Value!,
    Type: 'String',
    Overwrite: true,
    Description: `Rollback to ${targetParameter.Description}`
  });

  // Function'ları eski layer ile redeploy etmek için stack update tetikle
  const stackName = `FunctionStack-${config.environment}`;

  await cfn.updateStack({
    StackName: stackName,
    UsePreviousTemplate: true,
    Parameters: [
      {
        ParameterKey: 'ForceUpdate',
        ParameterValue: Date.now().toString()
      }
    ]
  });

  console.log(`Rollback başlatıldı. Stack ${stackName} güncelleniyor.`);
}

// Kullanım
rollbackLayer({
  environment: 'prod',
  layerName: 'monitoring',
  targetVersion: '2.3.1' // Opsiyonel
});

Version manifest yaklaşımı için rollback daha da basit:

# Önceki versiyona rollback
git revert HEAD
git push

# Belirli bir versiyona rollback
git checkout <commit-hash> config/layer-versions.yml
git commit -m "rollback: monitoring layer'ı v2.3.1'e geri al"
git push

# Eski layer versiyonunu almak için function stack'i redeploy et
npx cdk deploy FunctionStack-prod

Layer Test Stratejisi#

Layer’ları production’a terfi ettirmeden önce, gerçek function koduyla test et:

// layers/monitoring/__tests__/integration.test.ts
import { Lambda } from '@aws-sdk/client-lambda';
import { expect } from 'chai';

describe('Monitoring Layer Integration Tests', () => {
  const lambda = new Lambda({ region: 'us-east-1' });
  const testLayerArn = process.env.TEST_LAYER_ARN!;

  it('tüm layer dependency\'lerini başarıyla import etmeli', async () => {
    const testFunctionCode = `
      exports.handler = async (event) => {
        const pino = require('pino');
        const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
        const { datadogLambda } = require('datadog-lambda-js');

        return {
          statusCode: 200,
          body: JSON.stringify({
            dependencies: {
              pino: typeof pino !== 'undefined',
              dynamodb: typeof DynamoDBClient !== 'undefined',
              datadog: typeof datadogLambda !== 'undefined'
            }
          })
        };
      };
    `;

    // Layer ile test function oluştur
    const response = await lambda.createFunction({
      FunctionName: `layer-test-${Date.now()}`,
      Runtime: 'nodejs20.x',
      Role: process.env.TEST_LAMBDA_ROLE_ARN!,
      Handler: 'index.handler',
      Code: {
        ZipFile: Buffer.from(testFunctionCode)
      },
      Layers: [testLayerArn]
    });

    // Invoke et ve doğrula
    const invokeResult = await lambda.invoke({
      FunctionName: response.FunctionName!
    });

    const payload = JSON.parse(
      Buffer.from(invokeResult.Payload!).toString()
    );

    expect(payload.dependencies.pino).to.be.true;
    expect(payload.dependencies.dynamodb).to.be.true;
    expect(payload.dependencies.datadog).to.be.true;

    // Temizlik
    await lambda.deleteFunction({
      FunctionName: response.FunctionName!
    });
  });

  it('layer takılıyken invocation bütçesinin içinde kalmalı', async () => {
    // Ardışık invoke'lar execution environment'ı yeniden kullanır, yani bu
    // ölçüm steady-state süreyi verir. Her iterasyonda cold start zorlamak
    // için invoke'lar arasında function konfigürasyonunu güncellemek gerekir.
    const measurements: number[] = [];

    for (let i = 0; i < 10; i++) {
      const start = Date.now();
      await lambda.invoke({
        FunctionName: 'test-function-with-layer'
      });
      measurements.push(Date.now() - start);
    }

    const avgDuration = measurements.reduce((a, b) => a + b) / measurements.length;

    expect(avgDuration).to.be.lessThan(200);
  });
});

Yaygın Tuzaklar#

Deploy sırasında “latest” çözmek: Lambda her layer ARN’inde versiyon numarası istiyor, bu yüzden kısayol genellikle synthesis sırasında en son yayımlanan versiyonu seçen bir lookup oluyor. Dev’de pratik görünüyor; ta ki hatalı bir publish tüm fonksiyonları aynı anda ileri taşıyana ve tek bir fonksiyonu geride tutmanın yolu kalmayana kadar. Dev dahil her ortamda versiyonu pinle.

// Reddedilir: Lambda, layer ARN'inde versiyon numarası ister
const layer = LayerVersion.fromLayerVersionArn(
  this,
  'Layer',
  'arn:aws:lambda:us-east-1:123456789012:layer:monitoring'
);

// Bu ortamın test edildiği versiyona pinlenmiş
const layer = LayerVersion.fromLayerVersionArn(
  this,
  'Layer',
  'arn:aws:lambda:us-east-1:123456789012:layer:monitoring:12'
);

Örtüşen dependency’ler: Node, modülleri layer içeriğinin açıldığı /opt/nodejs/node_modules dizinine gitmeden önce function’ın kendi node_modules dizininde arıyor. Kendi paketinde lodash@4.17.21 taşıyan bir function, layer 4.17.20 gönderse bile kendi kopyasını kullanmayı sürdürüyor; yani layer’ı yamalamak, tam da kendi kopyasını taşıyan fonksiyonlarda hiçbir şey değiştirmemiş gibi görünüyor. Layer dependency’lerini exact versiyonlarla dokümante et ve function’ların layer’da zaten var olan bir paketi tanımlamasına izin verme.

// layers/monitoring/package.json
{
  "name": "monitoring-layer",
  "dependencies": {
    "pino": "8.15.0",
    "dd-trace": "4.20.0"
  }
}

// function/package.json - overlap'ten kaçın
{
  "name": "data-processor",
  "dependencies": {
    "zod": "3.22.4"  // Function'a özgü, conflict yok
  }
}

Layer boyutunun sessizce büyümesi: Layer’lar birer dependency ile büyüyor ve 50MB’lık zipped upload limiti hiçbir uyarı vermeden geliyor. Limiti aşan deployment, sıradaki hangi ortamsa orada patlıyor; genellikle de en son debug etmek isteyeceğin ortamda. 40MB’da (limitin %80’i) build’i düşüren bir CI kontrolü tepki vermek için alan bırakıyor:

# GitHub Actions layer boyut kontrolü
- name: Check layer size
  run: |
    LAYER_SIZE=$(wc -c < "dist/monitoring-layer.zip")
    MAX_SIZE=41943040  # 40MB (50MB limit'in %80'i)

    if [ $LAYER_SIZE -gt $MAX_SIZE ]; then
      echo "::error::Layer boyutu ${LAYER_SIZE} 40MB threshold'unu aşıyor"
      exit 1
    fi

Cross-account permission boşlukları: Tooling account’tan paylaşılan bir layer için tüketen account’a ayrıca lambda:GetLayerVersion izni verilmesi gerekiyor. Bu izin yoksa CDK deployment başarılı oluyor, invocation ise “Layer not found” hatasıyla düşüyor ve hata seni yanlış yere bakmaya götürüyor. Paylaşımdan hemen sonra erişimi doğrula:

// Layer erişimini doğrula scripti
async function verifyLayerAccess(
  layerArn: string,
  accountId: string
): Promise<void> {
  const lambda = new Lambda({ region: 'us-east-1' });

  const policy = await lambda.getLayerVersionPolicy({
    LayerName: layerArn.split(':layer:')[1].split(':')[0],
    VersionNumber: parseInt(layerArn.split(':').pop()!)
  });

  const policyDoc = JSON.parse(policy.Policy!);
  const hasAccess = policyDoc.Statement.some((stmt: any) =>
    stmt.Principal.AWS === accountId || stmt.Principal.AWS === '*'
  );

  if (!hasAccess) {
    throw new Error(`Account ${accountId} erişimi yok: ${layerArn}`);
  }
}

Strateji Karşılaştırması#

Hangi stratejinin nereye oturduğu:

StratejiKarmaşıklıkEsneklikEn İyi Kullanım
Semantic Versiyonlama (İsimlendirme)DüşükOrtaKüçük takımlar, basit deployment’lar
Ortama Özgü Stack’lerOrtaYüksekNet ortam sınırları
SSM Parameter StoreYüksekÇok YüksekDinamik ortamlar, çok layer
Version Manifest (YAML)OrtaYüksekGitOps workflow’ları, audit gereksinimleri

Öneri: Şunlardan biri geçerli değilse version manifest (Strateji D) ile başla:

  • Layer ve ortam sayısı elle düzenlenen bir dosyayı aştığında ya da güncel ARN’in repo dışından okunabilmesi gerektiğinde SSM Parameter Store kullan
  • Layer içerikleri ortamlar arasında versiyon numarasının ötesinde ayrışıyorsa ortama özgü stack’ler kullan
  • Birkaç layer’ı olan küçük projelerde semantic naming kullan

Manifest, terfinin review’dan geçmesi ve rollback’in tek bir revert olması gerektiğinde yerini hak ediyor. Hangi stratejide karar kılarsan kıl, dev dahil her ortamda explicit bir versiyon pinle ve CI’daki boyut kontrolünü koru; bu iki alışkanlık yukarıdaki hataların çoğunu engelliyor.

Kaynaklar#

İlgili yazılar