실습 예제 · 6
Lambda + API Gateway REST API
서버리스 HTTP 엔드포인트를 만듭니다. 이 실습에서 반드시 이해하고 넘어갈 것은 권한이 두 방향이라는 점입니다 — 함수가 다른 서비스를 호출할 때 쓰는 실행 역할과, API Gateway가 함수를 호출하도록 허용하는 리소스 기반 권한은 서로 다릅니다.
학습 목표
- Lambda 실행 역할과 리소스 기반 권한의 역할 차이를 설명할 수 있습니다.
- API Gateway REST API에 프록시 통합으로 함수를 연결할 수 있습니다.
- 스테이지 배포 개념과 변경이 반영되는 시점을 이해할 수 있습니다.
- 제한 시간·메모리·동시성 설정이 무엇을 바꾸는지 설명할 수 있습니다.
- 콜드 스타트가 생기는 조건과 완화 수단을 구분할 수 있습니다.
시나리오
내부 도구용 조회 API를 만듭니다. 트래픽은 평소 거의 없다가 특정 시간에만 몰리고, 서버를 상시 띄워 두고 싶지 않습니다. 이런 형태가 서버리스가 가장 잘 맞는 조건입니다.
GET /items로 항목 목록을 반환합니다.- 인증은 이 실습 범위 밖으로 두고, 나중에 붙일 자리만 확인합니다.
- 배포는 스테이지로 구분합니다.
아키텍처 개요
| 구성 요소 | 역할 | 권한 |
|---|---|---|
| Lambda 함수 | 요청을 처리하고 응답을 만든다 | 실행 역할 — 함수가 로그를 쓰고 다른 서비스를 호출할 권한 |
| API Gateway REST API | HTTP 요청을 받아 함수를 호출한다 | 리소스 기반 권한 — 함수 쪽에 "이 API가 나를 호출해도 된다"를 기록 |
프록시 통합(AWS_PROXY) |
요청 전체를 함수에 그대로 전달 | — |
| 스테이지 | 배포 단위이자 호출 URL의 일부 | — |
구성 단계
1 · 실행 역할
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
aws iam create-role \
--role-name Lab06ItemsFnRole \
--assume-role-policy-document file://lambda-trust.json
# 로그를 쓸 권한은 AWS 관리형 정책으로 최소한만 붙입니다.
aws iam attach-role-policy \
--role-name Lab06ItemsFnRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
2 · 함수 만들기
export const handler = async (event) => {
const items = [
{ id: 1, name: "alpha" },
{ id: 2, name: "beta" }
];
return {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ items, path: event.rawPath ?? event.path })
};
};
zip -q function.zip index.mjs
aws lambda create-function \
--function-name lab06-items \
--runtime nodejs22.x \
--role arn:aws:iam::123456789012:role/Lab06ItemsFnRole \
--handler index.handler \
--zip-file fileb://function.zip \
--timeout 10 \
--memory-size 256
aws lambda wait function-active-v2 --function-name lab06-items
3 · REST API 만들기
REGION=ap-northeast-2
ACCOUNT=123456789012
FN_ARN="arn:aws:lambda:$REGION:$ACCOUNT:function:lab06-items"
API_ID=$(aws apigateway create-rest-api \
--name lab06-items-api \
--query 'id' --output text)
ROOT_ID=$(aws apigateway get-resources \
--rest-api-id "$API_ID" \
--query 'items[?path==`/`].id' --output text)
RES_ID=$(aws apigateway create-resource \
--rest-api-id "$API_ID" \
--parent-id "$ROOT_ID" \
--path-part items \
--query 'id' --output text)
aws apigateway put-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method GET \
--authorization-type NONE
# 프록시 통합은 항상 POST 로 Lambda 를 호출합니다. 클라이언트의 메서드와는 별개입니다.
aws apigateway put-integration \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method GET \
--type AWS_PROXY \
--integration-http-method POST \
--uri "arn:aws:apigateway:$REGION:lambda:path/2015-03-31/functions/$FN_ARN/invocations"
4 · 호출 권한 부여
여기까지 만들어도 호출하면 실패합니다. 함수 쪽에 "이 API가 호출해도 된다"는 권한을 기록해야 합니다.
aws lambda add-permission \
--function-name lab06-items \
--statement-id apigw-invoke-items \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:$REGION:$ACCOUNT:$API_ID/*/GET/items"
# 실제로 정책이 붙었는지 확인합니다.
aws lambda get-policy --function-name lab06-items --query 'Policy' --output text
--source-arn을 생략하면 모든 API Gateway가 이 함수를 호출할 수 있게 됩니다.
특정 API와 경로로 좁히는 것이 최소 권한 원칙에 맞습니다.
5 · 스테이지 배포
aws apigateway create-deployment \
--rest-api-id "$API_ID" \
--stage-name dev
echo "https://$API_ID.execute-api.$REGION.amazonaws.com/dev/items"
검증 방법
# 1) 함수만 직접 호출해 로직을 확인합니다.
aws lambda invoke \
--function-name lab06-items \
--payload '{"path":"/items"}' \
--cli-binary-format raw-in-base64-out \
response.json
cat response.json
# 2) API Gateway 의 테스트 호출로 통합 구간을 확인합니다.
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method GET \
--query '[status, body]' --output json
# 3) 함수 설정과 동시성 상태
aws lambda get-function-configuration \
--function-name lab06-items \
--query '[Runtime, Timeout, MemorySize, State, LastUpdateStatus]' \
--output table
| 증상 | 확인할 곳 |
|---|---|
| 함수 직접 호출도 실패 | 코드와 핸들러 이름, 실행 역할의 로그 권한 |
| 직접 호출은 되고 API가 실패 | 리소스 기반 권한, 통합 URI, 통합 HTTP 메서드 |
| 테스트 호출은 되고 실제 URL이 실패 | 스테이지 배포 여부 |
| 응답이 이상한 형태로 나옴 | 프록시 통합이 요구하는 statusCode·body 구조 |
비용 고려
| 항목 | 성격 |
|---|---|
| Lambda 호출 | 호출 횟수와 실행 시간(메모리 크기가 곱해진다) |
| API Gateway 요청 | 요청 수와 전송량 |
| CloudWatch Logs | 수집량과 보존 기간. 보존 기간을 정하지 않으면 무기한 쌓인다 |
| 프로비저닝된 동시성 | 사용하지 않아도 준비된 만큼 발생한다 |
| 유휴 상태 | 호출이 없으면 실행 요금이 없다 |
메모리를 올리면 단위 시간당 요금은 오르지만 실행 시간이 짧아져 총액이 줄어드는 경우가 있습니다. CPU 바운드 작업이라면 메모리를 몇 단계 바꿔 가며 실행 시간을 재 보는 것이 가장 확실한 최적화입니다.
프로덕션 고려사항
- 인증을 붙입니다. IAM 인증, Lambda 권한 부여자, Amazon Cognito 등
요구에 맞는 방식을 고릅니다.
authorization-type NONE을 그대로 두지 않습니다. - 사용량 계획과 API 키로 클라이언트별 속도를 제한할 수 있습니다.
- 동시성을 관리합니다. 예약 동시성으로 한 함수가 계정 전체 동시성을 잠식하지 않게 막고, 지연에 민감한 함수에는 프로비저닝된 동시성으로 콜드 스타트를 줄입니다.
- 로그 보존 기간을 명시적으로 설정합니다.
- VPC 연결은 필요할 때만. VPC에 연결하면 인터넷이나 퍼블릭 AWS 엔드포인트로 나가기 위해 NAT 게이트웨이나 VPC 엔드포인트가 필요해집니다.
- 배포는 별칭과 버전으로. 별칭에 가중치를 주면 점진적 전환이 가능합니다.
- 동기 호출 페이로드 상한은 6 MB입니다. 큰 데이터를 주고받아야 하면 Amazon S3에 두고 키만 전달합니다.
정리 — 리소스 삭제
aws apigateway delete-rest-api --rest-api-id "$API_ID"
aws lambda delete-function --function-name lab06-items
aws logs delete-log-group --log-group-name /aws/lambda/lab06-items
aws iam detach-role-policy \
--role-name Lab06ItemsFnRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role --role-name Lab06ItemsFnRole
로그 그룹은 함수를 지워도 남습니다. 보존 기간을 설정하지 않았다면 계속 쌓이므로 함께 정리합니다.
자주 하는 실수
| 실수 | 증상 | 고치는 법 |
|---|---|---|
| 리소스 기반 권한을 안 붙임 | API 호출이 내부 서버 오류로 실패한다 | lambda add-permission으로 API를 허용한다 |
통합 HTTP 메서드를 GET으로 |
통합 호출이 실패한다 | 프록시 통합은 항상 POST다 |
| 스테이지를 배포하지 않음 | 변경이 반영되지 않는다 | create-deployment를 실행한다 |
| 응답 구조가 프록시 형식과 다름 | 본문이 그대로 나오지 않거나 오류가 난다 | statusCode·headers·body를 반환한다 |
--source-arn 생략 |
다른 API도 이 함수를 호출할 수 있다 | API ID와 경로까지 지정해 좁힌다 |
| 제한 시간을 기본 3초로 둠 | 느린 의존 호출에서 함수가 잘린다 | 실제 처리 시간을 재고 조정한다 |
| VPC에 연결해 두고 NAT 없음 | 외부 API 호출이 갑자기 멈춘다 | NAT 게이트웨이나 VPC 엔드포인트를 추가한다(실습 10) |
이어서 볼 곳
- 12장 · 서버리스와 애플리케이션 통합 Lambda 한도와 동시성, API Gateway, 이벤트 기반 통합을 정면으로 다룹니다.
- 실습 7 · SQS + Lambda 비동기 처리 같은 함수를 큐로 트리거해 동기와 비동기의 차이를 확인합니다.
- 실습 8 · EventBridge 이벤트 아키텍처 규칙과 대상으로 이벤트를 라우팅하는 또 다른 호출 경로입니다.
- 케이스 1 · EC2에 액세스 키를 심어 배포했다 실행 역할이 왜 액세스 키를 대체하는지 사고 사례로 확인합니다.
- 실습 9 · ECS Fargate 서비스 배포 태스크 역할과 태스크 실행 역할로 같은 권한 구분을 다시 확인합니다.
공식 문서 출처
- AWS Lambda API 레퍼런스 — CreateFunction — 제한 시간 기본 3초·최대 900초, 메모리 기본 128 MB와 CPU 동반 증가, 런타임 값
- AWS Lambda API 레퍼런스 — AddPermission
— 리소스 기반 정책에 호출 주체와
SourceArn을 기록하는 방식 - AWS Lambda 개발자 안내서 — 할당량 — 실행 시간·메모리·동기 호출 페이로드 상한
- Amazon API Gateway API 레퍼런스 — CreateRestApi — REST API 생성
- Amazon API Gateway API 레퍼런스 — PutIntegration
— 통합 유형(
AWS_PROXY등)과 통합 HTTP 메서드 - Amazon API Gateway API 레퍼런스 — CreateDeployment — 스테이지 배포가 있어야 변경이 반영된다는 동작