2026년 서버리스 AWS Lambda API 활용법

Ashley Innocent

Ashley Innocent

25 March 2026

2026년 서버리스 AWS Lambda API 활용법

요약

AWS Lambda API는 개발자가 서버리스 함수를 프로그래밍 방식으로 배포, 관리 및 호출할 수 있도록 지원합니다. 이 API는 IAM 인증, 함수 관리를 위한 RESTful 엔드포인트, 계정 수준의 동시성 제한과 함께 비동기 및 동기 호출 옵션을 사용합니다. 이 가이드에서는 인증 설정, 함수 배포, 호출 패턴, 이벤트 소스 매핑 및 프로덕션 서버리스 아키텍처 전략을 다룹니다.

소개

AWS Lambda는 1백만 명 이상의 활성 사용자를 위해 매월 수조 건의 요청을 처리합니다. 서버리스 애플리케이션, 자동화 도구 또는 이벤트 기반 아키텍처를 구축하는 개발자에게 Lambda API 통합은 선택 사항이 아니라 Infrastructure as Code(IaC) 및 CI/CD 파이프라인에 필수적입니다.

현실은 이렇습니다. 50개 이상의 Lambda 함수를 수동으로 관리하는 팀은 배포, 구성 업데이트 및 모니터링에 매주 10~15시간을 낭비합니다. 견고한 Lambda API 통합은 배포를 자동화하고, 블루/그린 릴리스를 구현하며, 수요에 따른 동적 확장을 가능하게 합니다.

이 가이드는 AWS Lambda API 통합 프로세스 전체를 안내합니다. IAM 인증, 함수 생성 및 배포, 호출 패턴(동기/비동기), 이벤트 소스 매핑, 계층형 아키텍처 및 프로덕션 배포 전략을 배우게 됩니다. 이 가이드가 끝나면 프로덕션 환경에서 바로 사용할 수 있는 Lambda 통합을 갖게 될 것입니다.

버튼

AWS Lambda API란 무엇인가요?

AWS Lambda는 서버리스 컴퓨팅 함수를 관리하기 위한 RESTful API를 제공합니다. 이 API는 다음을 처리합니다:

주요 기능

기능 설명
RESTful API 표준 HTTPS 엔드포인트
IAM 인증 AWS Signature Version 4
비동기 호출 요청을 보내고 응답을 기다리지 않는 이벤트 처리
동기 호출 요청-응답 패턴
이벤트 소스 200개 이상의 AWS 서비스 통합
레이어 공유 코드 및 종속성
버전/별칭 트래픽 전환 및 롤백
프로비저닝된 동시성 콜드 스타트 제거

Lambda 런타임 지원

런타임 버전 사용 사례
Node.js 18.x, 20.x API 백엔드, 이벤트 처리
Python 3.9, 3.10, 3.11 데이터 처리, ML 추론
Java 11, 17, 21 엔터프라이즈 애플리케이션
Go 1.x 고성능 API
Rust 1.x 저지연 함수
.NET 6, 8 Windows 워크로드
Ruby 3.x 웹 애플리케이션
커스텀 모든 컨테이너 기반 런타임

API 아키텍처 개요

Lambda는 AWS 서비스 API 구조를 사용합니다:

https://lambda.{region}.amazonaws.com/2015-03-31/

API 버전

버전 상태 사용 사례
2015-03-31 현재 모든 Lambda 작업
2018-01-31 런타임 API 커스텀 런타임 인터페이스

시작하기: 인증 설정

1단계: AWS 계정 및 IAM 사용자 생성

API에 접근하기 전에:

  1. AWS 콘솔 방문
  2. AWS 계정 생성
  3. IAM 콘솔 > 사용자 > 사용자 생성으로 이동
  4. Lambda 실행 정책 연결

2단계: IAM 자격 증명 생성

프로그래밍 방식 접근을 위한 액세스 키 생성:

# AWS CLI 방식
aws iam create-access-key --user-name lambda-deployer

# 출력: 안전하게 보관하세요
{
  "AccessKey": {
    "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  }
}

보안 참고: 자격 증명을 안전하게 저장하세요:

# ~/.aws/credentials
[lambda-deployer]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# 또는 환경 변수 사용
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="us-east-1"

3단계: AWS Signature Version 4 이해

모든 Lambda API 요청은 SigV4 서명을 필요로 합니다:

const crypto = require('crypto');

class AWSSigner {
  constructor(accessKeyId, secretAccessKey, region, service = 'lambda') {
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.region = region;
    this.service = service;
  }

  sign(request, body = null) {
    const now = new Date();
    const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
    const dateStamp = amzDate.slice(0, 8);

    // Task 1: Create canonical request
    const hashedPayload = body ? crypto.createHash('sha256').update(body).digest('hex') : 'UNSIGNED-PAYLOAD';
    const canonicalUri = request.path;
    const canonicalQuerystring = request.query || '';
    const canonicalHeaders = `host:${request.host}\nx-amz-date:${amzDate}\n`;
    const signedHeaders = 'host;x-amz-date';
    const canonicalRequest = `${request.method}\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${hashedPayload}`;

    // Task 2: Create string to sign
    const algorithm = 'AWS4-HMAC-SHA256';
    const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;
    const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
    const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${hash}`;

    // Task 3: Calculate signature
    const kDate = this.hmac(`AWS4${this.secretAccessKey}`, dateStamp);
    const kRegion = this.hmac(kDate, this.region);
    const kService = this.hmac(kRegion, this.service);
    const kSigning = this.hmac(kService, 'aws4_request');
    const signature = this.hmac(kSigning, stringToSign, 'hex');

    // Task 4: Add authorization header
    const authorizationHeader = `${algorithm} Credential=${this.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;

    return {
      'Authorization': authorizationHeader,
      'X-Amz-Date': amzDate,
      'X-Amz-Content-Sha256': hashedPayload
    };
  }

  hmac(key, string, encoding = 'buffer') {
    return crypto.createHmac('sha256', key).update(string).digest(encoding);
  }
}

// 사용법
const signer = new AWSSigner(
  process.env.AWS_ACCESS_KEY_ID,
  process.env.AWS_SECRET_ACCESS_KEY,
  'us-east-1'
);

4단계: Lambda API 클라이언트 생성

const LAMBDA_BASE_URL = 'https://lambda.us-east-1.amazonaws.com/2015-03-31';

const lambdaRequest = async (path, options = {}) => {
  const url = new URL(`${LAMBDA_BASE_URL}${path}`);
  const method = options.method || 'GET';
  const body = options.body ? JSON.stringify(options.body) : null;

  const signer = new AWSSigner(
    process.env.AWS_ACCESS_KEY_ID,
    process.env.AWS_SECRET_ACCESS_KEY,
    'us-east-1'
  );

  const headers = signer.sign({ method, host: 'lambda.us-east-1.amazonaws.com', path }, body);

  const response = await fetch(url.toString(), {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...headers,
      ...options.headers
    },
    body
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Lambda API Error: ${error.Message}`);
  }

  return response.json();
};

// 사용법
const functions = await lambdaRequest('/functions');
console.log(`함수 ${functions.Functions.length}개를 찾았습니다`);

대안: AWS SDK 사용

프로덕션 사용을 위해 AWS SDK는 서명을 자동으로 처리합니다:

const { LambdaClient, ListFunctionsCommand, CreateFunctionCommand, InvokeCommand } = require('@aws-sdk/client-lambda');

const lambda = new LambdaClient({ region: 'us-east-1' });

// 함수 목록 조회
const listCommand = new ListFunctionsCommand({});
const result = await lambda.send(listCommand);

// 함수 생성
const createCommand = new CreateFunctionCommand({
  FunctionName: 'my-function',
  Runtime: 'nodejs20.x',
  Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  Handler: 'index.handler',
  Code: {
    S3Bucket: 'my-bucket',
    S3Key: 'function.zip'
  }
});

const fn = await lambda.send(createCommand);

함수 관리

함수 생성

API를 통해 Lambda 함수 생성:

const createFunction = async (functionConfig) => {
  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionConfig.name,
      Runtime: functionConfig.runtime || 'nodejs20.x',
      Role: functionConfig.roleArn,
      Handler: functionConfig.handler || 'index.handler',
      Code: {
        S3Bucket: functionConfig.s3Bucket,
        S3Key: functionConfig.s3Key
      },
      Description: functionConfig.description || '',
      Timeout: functionConfig.timeout || 3,
      MemorySize: functionConfig.memorySize || 128,
      Environment: {
        Variables: functionConfig.environment || {}
      },
      Tags: functionConfig.tags || {}
    }
  });

  return response;
};

// 사용법
const fn = await createFunction({
  name: 'order-processor',
  roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  handler: 'index.handler',
  runtime: 'nodejs20.x',
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'order-processor/v1.0.0.zip',
  description: 'Process orders from SQS queue',
  timeout: 30,
  memorySize: 512,
  environment: {
    DB_HOST: 'db.example.com',
    LOG_LEVEL: 'info'
  }
});

console.log(`함수가 생성되었습니다: ${fn.FunctionArn}`);

코드 직접 업로드

작은 함수(<50MB 압축)의 경우:

const fs = require('fs');
const path = require('path');

const createFunctionWithZip = async (functionName, zipPath) => {
  const zipBuffer = fs.readFileSync(zipPath);
  const base64Code = zipBuffer.toString('base64');

  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionName,
      Runtime: 'nodejs20.x',
      Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
      Handler: 'index.handler',
      Code: {
        ZipFile: base64Code
      }
    }
  });

  return response;
};

// 함수 패키징
// zip -r function.zip index.js node_modules/
await createFunctionWithZip('my-function', './function.zip');

함수 코드 업데이트

새 코드 버전 배포:

const updateFunctionCode = async (functionName, updateConfig) => {
  const response = await lambdaRequest(`/functions/${functionName}/code`, {
    method: 'PUT',
    body: {
      S3Bucket: updateConfig.s3Bucket,
      S3Key: updateConfig.s3Key,
      Publish: updateConfig.publish || false
    }
  });

  return response;
};

// 사용법
const updated = await updateFunctionCode('order-processor', {
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'order-processor/v1.1.0.zip',
  publish: true // 새 버전 생성
});

console.log(`다음 버전으로 업데이트되었습니다: ${updated.Version}`);

함수 구성 업데이트

타임아웃, 메모리, 환경 수정:

const updateFunctionConfig = async (functionName, config) => {
  const response = await lambdaRequest(`/functions/${functionName}/configuration`, {
    method: 'PUT',
    body: {
      Runtime: config.runtime,
      Handler: config.handler,
      Description: config.description,
      Timeout: config.timeout,
      MemorySize: config.memorySize,
      Environment: {
        Variables: config.environment
      }
    }
  });

  return response;
};

// 사용법
const updated = await updateFunctionConfig('order-processor', {
  timeout: 60,
  memorySize: 1024,
  environment: {
    DB_HOST: 'new-db.example.com',
    LOG_LEVEL: 'debug'
  }
});

함수 삭제

함수 제거:

const deleteFunction = async (functionName, qualifier = null) => {
  const path = qualifier
    ? `/functions/${functionName}?Qualifier=${qualifier}`
    : `/functions/${functionName}`;

  await lambdaRequest(path, { method: 'DELETE' });
  console.log(`함수 ${functionName}가 삭제되었습니다`);
};

함수 호출

동기 호출 (요청-응답)

함수를 호출하고 응답을 기다립니다:

const invokeFunction = async (functionName, payload, qualifier = null) => {
  const path = qualifier
    ? `/functions/${functionName}/invocations?Qualifier=${qualifier}`
    : `/functions/${functionName}/invocations`;

  const response = await lambdaRequest(path, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'RequestResponse', // 동기
      'X-Amz-Log-Type': 'Tail' // 로그 포함
    },
    body: payload
  });

  // 응답 파싱
  const result = JSON.parse(Buffer.from(response.Payload).toString());
  const logs = Buffer.from(response.LogResult, 'base64').toString();

  return { result, logs };
};

// 사용법
const { result, logs } = await invokeFunction('order-processor', {
  orderId: 'ORD-12345',
  customerId: 'CUST-67890',
  items: [
    { sku: 'PROD-001', quantity: 2 },
    { sku: 'PROD-002', quantity: 1 }
  ]
});

console.log(`결과: ${JSON.stringify(result)}`);
console.log(`로그:\n${logs}`);

비동기 호출 (요청 후 응답 대기 없음)

기다리지 않고 함수를 호출합니다:

const invokeAsync = async (functionName, payload) => {
  const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'Event', // 비동기
      'X-Amz-Log-Type': 'None'
    },
    body: payload
  });

  return {
    statusCode: response.StatusCode,
    executionId: response['X-Amz-Execution-Id']
  };
};

// 사용법 - 비동기 처리 트리거
const result = await invokeAsync('email-sender', {
  to: 'customer@example.com',
  template: 'order-confirmation',
  data: { orderId: 'ORD-12345' }
});

console.log(`비동기 호출 ID: ${result.executionId}`);

드라이 런 호출

실행하지 않고 권한 테스트:

const dryRunInvocation = async (functionName) => {
  const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'DryRun'
    }
  });

  return response;
};

// 사용법 - IAM 권한 확인
try {
  await dryRunInvocation('order-processor');
  console.log('호출 권한 확인 완료');
} catch (error) {
  console.error('권한 거부됨:', error.message);
}

호출 응답 유형

호출 유형 동작 사용 사례
RequestResponse 동기, 결과 대기 API 호출, CLI 명령
Event 비동기, 요청 후 응답 대기 없음 이벤트 처리, 알림
DryRun 권한만 테스트 검증, 디버깅

버전 및 별칭 관리

버전 게시

불변하는 함수 버전 생성:

const publishVersion = async (functionName, description = null) => {
  const response = await lambdaRequest(`/functions/${functionName}/versions`, {
    method: 'POST',
    body: description ? { Description: description } : {}
  });

  return response;
};

// 사용법
const version = await publishVersion('order-processor', 'v1.2.0 - Add tax calculation');
console.log(`게시된 버전: ${version.Version}`);

별칭 생성

버전에 대한 명명된 포인터 생성:

const createAlias = async (functionName, aliasName, version, description = null) => {
  const response = await lambdaRequest(`/functions/${functionName}/aliases`, {
    method: 'POST',
    body: {
      Name: aliasName,
      FunctionVersion: version,
      Description: description
    }
  });

  return response;
};

// 사용법 - 프로덕션 별칭 생성
const prodAlias = await createAlias('order-processor', 'prod', '5', 'Production version');
console.log(`별칭 ARN: ${prodAlias.AliasArn}`);

라우팅 구성으로 트래픽 전환

새 버전으로 트래픽을 점진적으로 전환:

const updateAliasWithRouting = async (functionName, aliasName, routingConfig) => {
  const response = await lambdaRequest(`/functions/${functionName}/aliases/${aliasName}`, {
    method: 'PUT',
    body: {
      RoutingConfig: {
        AdditionalVersionWeights: routingConfig
      }
    }
  });

  return response;
};

// 사용법 - 버전 6에 10% 트래픽, 버전 5에 90% 트래픽
await updateAliasWithRouting('order-processor', 'prod', {
  '6': 0.1
});

// 검증 후 100%로 전환
await updateAliasWithRouting('order-processor', 'prod', {});

별칭 사용 사례

별칭 버전 목적
dev $LATEST 개발 테스트
staging 최근 테스트된 QA 검증
prod 안정 버전 프로덕션 트래픽
blue 현재 프로덕션 블루/그린 배포
green 새 버전 블루/그린 배포

이벤트 소스 매핑

SQS 트리거 생성

SQS 큐를 Lambda에 연결:

const createSQSEventSource = async (functionName, queueArn, batchSize = 10) => {
  const response = await lambdaRequest('/event-source-mappings', {
    method: 'POST',
    body: {
      EventSourceArn: queueArn,
      FunctionName: functionName,
      BatchSize: batchSize,
      Enabled: true
    }
  });

  return response;
};

// 사용법
const mapping = await createSQSEventSource(
  'order-processor',
  'arn:aws:sqs:us-east-1:123456789012:orders-queue',
  10
);

console.log(`이벤트 소스가 생성되었습니다: ${mapping.UUID}`);

DynamoDB 스트림 트리거 생성

DynamoDB 스트림을 Lambda에 연결:

const createDynamoDBEventSource = async (functionName, streamArn, startingPosition = 'LATEST') => {
  const response = await lambdaRequest('/event-source-mappings', {
    method: 'POST',
    body: {
      EventSourceArn: streamArn,
      FunctionName: functionName,
      StartingPosition: startingPosition,
      BatchSize: 100,
      BisectBatchOnFunctionError: true,
      MaximumRetryAttempts: 3
    }
  });

  return response;
};

// 사용법
await createDynamoDBEventSource(
  'user-analytics',
  'arn:aws:dynamodb:us-east-1:123456789012:table/Users/stream/2026-03-25T00:00:00.000'
);

이벤트 소스 유형

소스 사용 사례 배치 지원
SQS 메시지 큐 예 (1-10)
Kinesis 실시간 스트림 예 (1-10,000)
DynamoDB 스트림 데이터베이스 변경 예 (1-1,000)
S3 객체 이벤트 아니요 (이벤트당 1개)
EventBridge 이벤트 라우팅
API Gateway HTTP API 아니요
스케줄 크론 작업 아니요

레이어 관리

레이어 생성

공유 코드/종속성 패키징:

const createLayer = async (layerName, layerConfig) => {
  const response = await lambdaRequest('/layers', {
    method: 'POST',
    body: {
      LayerName: layerName,
      Description: layerConfig.description,
      CompatibleRuntimes: layerConfig.runtimes,
      Content: {
        S3Bucket: layerConfig.s3Bucket,
        S3Key: layerConfig.s3Key
      }
    }
  });

  return response;
};

// 사용법
const layer = await createLayer('shared-utils', {
  description: 'Shared utilities and dependencies',
  runtimes: ['nodejs20.x', 'nodejs18.x'],
  s3Bucket: 'my-layers-bucket',
  s3Key: 'shared-utils/v1.zip'
});

console.log(`레이어 ARN: ${layer.LayerArn}`);

함수에서 레이어 사용

함수에 레이어 연결:

const createFunctionWithLayers = async (functionConfig) => {
  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionConfig.name,
      Runtime: functionConfig.runtime,
      Role: functionConfig.roleArn,
      Handler: functionConfig.handler,
      Code: {
        S3Bucket: functionConfig.s3Bucket,
        S3Key: functionConfig.s3Key
      },
      Layers: functionConfig.layers // Array of layer ARNs
    }
  });

  return response;
};

// 사용법
await createFunctionWithLayers({
  name: 'api-handler',
  roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  handler: 'index.handler',
  runtime: 'nodejs20.x',
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'api-handler/v1.0.0.zip',
  layers: [
    'arn:aws:lambda:us-east-1:123456789012:layer:shared-utils:1',
    'arn:aws:lambda:us-east-1:123456789012:layer:aws-sdk:3'
  ]
});

동시성 및 스케일링

예약된 동시성 설정

핵심 함수를 위한 용량 예약:

const putFunctionConcurrency = async (functionName, reservedConcurrentExecutions) => {
  const response = await lambdaRequest(`/functions/${functionName}/concurrency`, {
    method: 'PUT',
    body: {
      ReservedConcurrentExecutions: reservedConcurrentExecutions
    }
  });

  return response;
};

// 사용법 - 100개의 동시 실행 예약
await putFunctionConcurrency('order-processor', 100);

계정 동시성 제한

계정 유형 기본 제한 증대 가능 여부
프리 티어 1,000
종량제 1,000
엔터프라이즈 1,000+ 사용자 지정 제한

프로덕션 배포 체크리스트

프로덕션에 배포하기 전에:

실제 사용 사례

API 백엔드

한 SaaS 회사가 서버리스 REST API를 구축합니다:

주요 구현:

이벤트 처리 파이프라인

한 전자상거래 플랫폼이 주문을 처리합니다:

주요 구현:

결론

AWS Lambda API는 포괄적인 서버리스 컴퓨팅 기능을 제공합니다. 주요 요점은 다음과 같습니다:

버튼

FAQ 섹션

Lambda API로 어떻게 인증하나요?

Signature Version 4 서명을 사용하는 AWS IAM 자격 증명을 사용하세요. AWS SDK는 서명을 자동으로 처리합니다.

동기 및 비동기 호출의 차이점은 무엇인가요?

동기식(RequestResponse)은 함수 완료를 기다리고 결과를 반환합니다. 비동기식(Event)은 요청을 대기열에 넣고 즉시 반환합니다.

Lambda 버전은 어떻게 작동하나요?

게시된 각 버전은 함수의 불변 스냅샷입니다. 별칭을 사용하여 특정 버전을 가리키고 트래픽 전환을 활성화하세요.

Lambda 레이어는 무엇인가요?

레이어는 함수 코드와 별도로 코드 및 종속성을 패키징하여 여러 함수에서 공유 라이브러리를 사용할 수 있도록 합니다.

콜드 스타트를 줄이려면 어떻게 해야 하나요?

지연 시간에 민감한 함수에는 프로비저닝된 동시성, 더 작은 배포 패키지, 컴파일된 언어(Go, Rust)를 사용하세요.

예약된 동시성이란 무엇인가요?

예약된 동시성은 특정 함수에 대한 실행 슬롯을 보장하여 시끄러운 이웃 문제를 방지합니다.

S3에서 Lambda를 트리거할 수 있나요?

예, S3 이벤트 알림을 구성하여 객체 생성/삭제 시 Lambda를 호출할 수 있습니다.

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요