$ yh.log
AWS SAM 정리

AWS SAM 정리

AWSSAMServerlessDVA-C02

작성자 : 오예환 | 작성일 : 2026-01-18 | 수정일 : 2026-01-18

1. AWS SAM 개요

🤔 SAM이 뭔가요?

비유로 이해하기: SAM은 서버리스 앱의 설계도 템플릿입니다.

  • 집을 지을 때 설계도가 필요하듯이
  • Lambda + API Gateway + DynamoDB를 만들 때 간단한 YAML 파일 하나로!
  • 복잡한 CloudFormation을 자동으로 생성해줌

SAM = Serverless Application Model

┌─────────────────────────────────────────────────────────────────┐
                      SAM의 역할

  기존 방식 (CloudFormation 직접 작성):                          │
  ┌────────────────────────────────────────────────────┐
  200줄의 복잡한 YAML...
  Lambda 정의, IAM Role 정의, API Gateway 정의,
  권한 연결, 이벤트 매핑...
  └────────────────────────────────────────────────────┘

  SAM 사용:
  ┌────────────────────────────────────────────────────┐
  20줄의 간단한 YAML!
  AWS::Serverless::Function 하나면 끝!
  └────────────────────────────────────────────────────┘

 자동 변환
  ┌────────────────────────────────────────────────────┐
  복잡한 CloudFormation 템플릿 자동 생성!
  └────────────────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

SAM 특징

특징설명초보자 설명
YAML 기반모든 설정을 YAML로읽기 쉽고 버전 관리 가능
CloudFormation 확장CF의 모든 기능 사용 가능Outputs, Parameters 등
로컬 테스트로컬에서 Lambda 실행배포 전 테스트 가능!
CodeDeploy 통합안전한 배포Canary, Linear 배포

SAM이 지원하는 것

기능설명
Lambda서버리스 함수
API GatewayREST/HTTP API
DynamoDBNoSQL 데이터베이스
Step Functions워크플로우
EventBridge이벤트 버스
SQS, SNS메시징

2. SAM 기본 구조

SAM 템플릿 핵심 요소

# template.yaml
 
# 1. SAM 템플릿임을 선언 (필수!)
Transform: "AWS::Serverless-2016-10-31"
 
# 2. 설명
Description: My Serverless Application
 
# 3. 전역 설정 (선택)
Globals:
  Function:
    Timeout: 30
    Runtime: nodejs18.x
 
# 4. 리소스 정의 (핵심!)
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      CodeUri: ./src
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /hello
            Method: get
 
# 5. 출력 (선택)
Outputs:
  ApiUrl:
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

SAM 전용 리소스 타입

타입설명CloudFormation 대응
AWS::Serverless::FunctionLambda 함수Lambda + IAM Role + ...
AWS::Serverless::ApiAPI Gateway REST APIAPI Gateway + Stage + ...
AWS::Serverless::HttpApiAPI Gateway HTTP APIHTTP API + Stage + ...
AWS::Serverless::SimpleTableDynamoDB 테이블DynamoDB (단순 버전)
AWS::Serverless::LayerVersionLambda LayerLambda Layer
AWS::Serverless::Application중첩 애플리케이션Nested Stack

Transform 헤더

# ⚠️ 이 줄이 있어야 SAM 템플릿으로 인식됨!
Transform: "AWS::Serverless-2016-10-31"

초보자 설명: 이 줄이 CloudFormation에게 "이건 SAM 템플릿이야, SAM 리소스를 변환해줘"라고 알려줍니다.


3. SAM 배포 과정

🤔 어떻게 배포하나요?

배포 흐름

┌─────────────────────────────────────────────────────────────────┐
                    SAM 배포 과정

  1. 빌드 (sam build)                                            │
  ┌─────────────────┐
  SAM Template
   (YAML)        │                                            │
  + 소스 코드
  └────────┬────────┘

 sam build

  2. 패키지 & 배포 (sam deploy)                                   │
  ┌─────────────────┐     ┌─────────────────┐
  .aws-sam/    S3 Bucket
  build/         │────→│  (코드 업로드)   │                   │
  └────────┬────────┘     └────────┬────────┘

 transform
  ┌─────────────────┐
 CloudFormation  │←─────────────┘
   Template
  └────────┬────────┘

 create/update stack

  3. CloudFormation 스택 생성
  ┌─────────────────────────────────────────────────┐
         CloudFormation Stack
  ┌─────────┐ ┌─────────┐ ┌─────────────┐
 Lambda   API  DynamoDB
  │Function Gateway   Table
  └─────────┘ └─────────┘ └─────────────┘
  └─────────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

SAM CLI 명령어

# 1. 프로젝트 초기화
sam init
 
# 2. 빌드 (의존성 설치 + 패키징)
sam build
 
# 3. 배포 (첫 배포 시 --guided 옵션 추가)
sam deploy --guided
 
# 4. 이후 배포 (설정 저장됨)
sam deploy

sam deploy --guided

┌─────────────────────────────────────────────────────────────────┐
                    sam deploy --guided

 배포 대화형으로 설정:

  Stack Name [sam-app]: my-app                                   │
  AWS Region [us-east-1]: ap-northeast-2                        │
  Confirm changes before deploy [y/N]: y                        │
  Allow SAM CLI IAM role creation [Y/n]: Y                      │
  Save arguments to configuration file [Y/n]: Y                 │

 samconfig.toml 파일에 설정 저장됨!
 다음부터 sam deploy만 실행하면

└─────────────────────────────────────────────────────────────────┘

4. SAM Accelerate (sam sync)

🤔 sam sync가 뭔가요?

비유로 이해하기: 핫 리로드와 같습니다.

  • 기존: 코드 수정 → sam build → sam deploy → 5분 대기...
  • sam sync: 코드 수정 → 몇 초 만에 AWS에 반영!

sam deploy vs sam sync

항목sam deploysam sync
방식CloudFormation 통해 배포직접 API 호출
속도느림 (분 단위)빠름 (초 단위)
용도프로덕션 배포개발 중 빠른 테스트
안전성높음 (변경 세트)낮음 (직접 업데이트)

sam sync 옵션들

# 1. 코드 + 인프라 모두 동기화
sam sync
 
# 2. 코드만 동기화 (CloudFormation 우회, 매우 빠름!)
sam sync --code
 
# 3. Lambda 함수만 동기화
sam sync --code --resource AWS::Serverless::Function
 
# 4. 특정 리소스만 동기화
sam sync --code --resource-id HelloWorldLambdaFunction
 
# 5. 파일 변경 감지 + 자동 동기화 (개발 시 최고!)
sam sync --watch

sam sync --watch (개발 필수!)

┌─────────────────────────────────────────────────────────────────┐
                    sam sync --watch

  터미널:
  $ sam sync --watch
  Watching for file changes...

  ┌──────────────────────┐
  src/index.js 수정
  └──────────┬───────────┘

 자동 감지!

  코드만 변경됨 sam sync --code 자동 실행
  인프라 변경됨 sam sync 자동 실행

 저장하면 만에 AWS에 반영!

└─────────────────────────────────────────────────────────────────┘

5. SAM Policy Templates

🤔 Policy Templates가 뭔가요?

비유로 이해하기: 미리 만들어진 권한 세트입니다.

  • 직접 IAM 정책 작성하면 복잡하고 실수하기 쉬움
  • SAM이 자주 쓰는 권한 조합을 템플릿으로 제공!

자주 쓰는 Policy Templates

템플릿설명사용 사례
S3ReadPolicyS3 읽기 전용파일 다운로드
S3WritePolicyS3 쓰기파일 업로드
S3CrudPolicyS3 CRUD모든 S3 작업
DynamoDBReadPolicyDynamoDB 읽기데이터 조회
DynamoDBCrudPolicyDynamoDB CRUD모든 DB 작업
SQSPollerPolicySQS 폴링메시지 수신
SQSSendMessagePolicySQS 전송메시지 발송
SNSPublishMessagePolicySNS 발행알림 전송
LambdaInvokePolicyLambda 호출다른 Lambda 실행
StepFunctionsExecutionPolicyStep Functions 실행워크플로우 시작

사용 예시

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      CodeUri: ./src
 
      # Policy Templates 사용!
      Policies:
        # S3 버킷 읽기 권한
        - S3ReadPolicy:
            BucketName: !Ref MyBucket
 
        # DynamoDB 테이블 CRUD 권한
        - DynamoDBCrudPolicy:
            TableName: !Ref MyTable
 
        # SQS 큐 폴링 권한
        - SQSPollerPolicy:
            QueueName: !GetAtt MyQueue.QueueName

직접 작성 vs Policy Template

# ❌ 직접 IAM 정책 작성 (복잡하고 실수 가능)
Policies:
  - Version: '2012-10-17'
    Statement:
      - Effect: Allow
        Action:
          - dynamodb:GetItem
          - dynamodb:PutItem
          - dynamodb:UpdateItem
          - dynamodb:DeleteItem
          - dynamodb:Query
          - dynamodb:Scan
        Resource: !GetAtt MyTable.Arn
 
# ✅ Policy Template 사용 (간단!)
Policies:
  - DynamoDBCrudPolicy:
      TableName: !Ref MyTable

6. SAM과 CodeDeploy 통합

🤔 왜 CodeDeploy가 필요한가요?

비유로 이해하기: 점진적 출시와 같습니다.

  • 새 버전을 한 번에 모든 사용자에게 배포하면 위험!
  • 조금씩 트래픽을 새 버전으로 이동
  • 문제 발생 시 자동 롤백

Traffic Shifting (트래픽 전환)

┌─────────────────────────────────────────────────────────────────┐
                    Traffic Shifting 과정

  배포 전:
  Lambda Alias (LIVE) ──100%──→ Version 1 (기존)                │

  Canary 배포 시작 (10% 전환):                                   │
  Lambda Alias (LIVE) ──90%───→ Version 1 (기존)                │
                      ──10%───→ Version 2 (신규)                │

  문제 없으면 (10분 ):                                         │
  Lambda Alias (LIVE) ──0%────→ Version 1 (기존)                │
                      ──100%──→ Version 2 (신규)                │

  ⚠️ 문제 발생 시:
  CloudWatch Alarm 트리거 자동 롤백!
  Lambda Alias (LIVE) ──100%──→ Version 1 (원복)                │

└─────────────────────────────────────────────────────────────────┘

배포 전략

전략설명예시
AllAtOnce즉시 100% 전환개발/테스트 환경
CanaryX% 먼저, 대기, 나머지Canary10Percent5Minutes
Linear일정 간격으로 X%씩Linear10PercentEvery1Minute

SAM 템플릿 설정

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      CodeUri: ./src
 
      # 자동으로 버전 생성 + Alias 연결
      AutoPublishAlias: live
 
      # 배포 설정
      DeploymentPreference:
        # 배포 전략: 10%로 5분 테스트 후 100%
        Type: Canary10Percent5Minutes
 
        # 롤백 조건 (CloudWatch Alarm)
        Alarms:
          - !Ref MyAlarm
 
        # 배포 전 테스트 함수
        Hooks:
          PreTraffic: !Ref PreTrafficHook
          PostTraffic: !Ref PostTrafficHook

Hooks (배포 전/후 테스트)

┌─────────────────────────────────────────────────────────────────┐
                    Deployment Hooks

  1. PreTraffic Hook (트래픽 전환)                            │
     ├─ 버전 함수 테스트
     ├─ DB 마이그레이션 확인
     └─ 테스트 실패 배포 중단!

  2. Traffic Shifting (점진적 전환)                              │
     └─ 10% 20% ... 100%

  3. PostTraffic Hook (전환 완료)                             │
     ├─ 통합 테스트 실행
     ├─ 성능 테스트
     └─ 테스트 실패 롤백!

└─────────────────────────────────────────────────────────────────┘

Hook 함수 예시

Resources:
  # Pre-Traffic Hook Lambda
  PreTrafficHook:
    Type: AWS::Serverless::Function
    Properties:
      Handler: preTraffic.handler
      Runtime: nodejs18.x
      CodeUri: ./hooks
      Policies:
        - Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - codedeploy:PutLifecycleEventHookExecutionStatus
              Resource: "*"
      Environment:
        Variables:
          NewVersion: !Ref MyFunction.Version
// hooks/preTraffic.js
const AWS = require("aws-sdk");
const lambda = new AWS.Lambda();
const codedeploy = new AWS.CodeDeploy();
 
exports.handler = async event => {
  const deploymentId = event.DeploymentId;
  const lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId;
 
  try {
    // 새 버전 Lambda 테스트
    const result = await lambda
      .invoke({
        FunctionName: process.env.NewVersion,
        Payload: JSON.stringify({ test: true }),
      })
      .promise();
 
    // 테스트 성공!
    await codedeploy
      .putLifecycleEventHookExecutionStatus({
        deploymentId,
        lifecycleEventHookExecutionId,
        status: "Succeeded",
      })
      .promise();
  } catch (error) {
    // 테스트 실패 → 배포 중단
    await codedeploy
      .putLifecycleEventHookExecutionStatus({
        deploymentId,
        lifecycleEventHookExecutionId,
        status: "Failed",
      })
      .promise();
  }
};

7. SAM 로컬 테스트

🤔 로컬에서 테스트할 수 있나요?

비유로 이해하기: 배포하기 전에 내 컴퓨터에서 미리 테스트!

  • Lambda를 AWS에 배포하지 않고 로컬에서 실행
  • API Gateway도 로컬에서 에뮬레이션

로컬 테스트 명령어

1️⃣ Lambda 함수 한 번 실행

# 기본 실행
sam local invoke MyFunction
 
# 이벤트 데이터와 함께 실행
sam local invoke MyFunction -e events/event.json
 
# 환경 변수 파일과 함께
sam local invoke MyFunction --env-vars env.json

2️⃣ Lambda 로컬 엔드포인트 (지속 실행)

# Lambda 로컬 서버 시작
sam local start-lambda
 
# 다른 터미널에서 AWS CLI로 호출
aws lambda invoke \
  --function-name MyFunction \
  --endpoint-url http://127.0.0.1:3001 \
  --payload '{"key": "value"}' \
  response.json

3️⃣ API Gateway 로컬 실행

# API Gateway 로컬 서버 시작
sam local start-api
 
# 브라우저 또는 curl로 테스트
curl http://127.0.0.1:3000/hello
┌─────────────────────────────────────────────────────────────────┐
                    sam local start-api

  $ sam local start-api
  Mounting MyFunction at http://127.0.0.1:3000/hello [GET]      │
  Starting local HTTP server...

  ┌────────────────┐      ┌────────────────┐
   브라우저      │─────→│   로컬 API
 localhost:3000   Gateway
  └────────────────┘      └───────┬────────┘


                          ┌────────────────┐
  Docker 컨테이너
  (Lambda 실행)  │                    │
                          └────────────────┘

  ⚠️ Docker가 설치되어 있어야 함!

└─────────────────────────────────────────────────────────────────┘

4️⃣ 이벤트 생성

# S3 PUT 이벤트 생성
sam local generate-event s3 put --bucket my-bucket --key test.txt
 
# API Gateway 이벤트 생성
sam local generate-event apigateway aws-proxy --path /hello --method GET
 
# DynamoDB Stream 이벤트 생성
sam local generate-event dynamodb update
 
# 이벤트를 Lambda에 바로 전달
sam local generate-event s3 put --bucket my-bucket --key test.txt | \
  sam local invoke MyFunction -e -

지원하는 이벤트 소스

소스명령어 예시
S3generate-event s3 put
API Gatewaygenerate-event apigateway aws-proxy
SNSgenerate-event sns notification
SQSgenerate-event sqs receive-message
DynamoDBgenerate-event dynamodb update
Kinesisgenerate-event kinesis get-records
CloudWatchgenerate-event cloudwatch scheduled-event

8. SAM 다중 환경 설정

🤔 개발/운영 환경을 어떻게 나누나요?

samconfig.toml 사용

# samconfig.toml
 
# 기본 설정 (sam deploy 시 사용)
[default.deploy.parameters]
stack_name = "my-app-prod"
region = "ap-northeast-2"
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
 
# 개발 환경 설정
[dev.deploy.parameters]
stack_name = "my-app-dev"
region = "ap-northeast-2"
capabilities = "CAPABILITY_IAM"
confirm_changeset = false
parameter_overrides = "Environment=dev"
 
# 스테이징 환경 설정
[staging.deploy.parameters]
stack_name = "my-app-staging"
region = "ap-northeast-2"
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
parameter_overrides = "Environment=staging"
 
# 프로덕션 환경 설정
[prod.deploy.parameters]
stack_name = "my-app-prod"
region = "ap-northeast-2"
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
parameter_overrides = "Environment=prod"

환경별 배포

# 개발 환경 배포
sam deploy --config-env dev
 
# 스테이징 환경 배포
sam deploy --config-env staging
 
# 프로덕션 환경 배포
sam deploy --config-env prod

템플릿에서 환경 변수 사용

# template.yaml
Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod
 
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs18.x
      Environment:
        Variables:
          ENV: !Ref Environment
          TABLE_NAME: !Sub "${Environment}-my-table"

9. SAM 실전 예시

완전한 SAM 템플릿 예시

# template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: My Serverless API
 
# 파라미터
Parameters:
  Environment:
    Type: String
    Default: dev
 
# 전역 설정
Globals:
  Function:
    Timeout: 30
    Runtime: nodejs18.x
    MemorySize: 256
    Environment:
      Variables:
        TABLE_NAME: !Ref MyTable
 
# 리소스
Resources:
  # API Gateway
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Environment
      Cors:
        AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
        AllowHeaders: "'Content-Type,Authorization'"
        AllowOrigin: "'*'"
 
  # Lambda 함수
  GetItemsFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/getItems.handler
      CodeUri: .
      Policies:
        - DynamoDBReadPolicy:
            TableName: !Ref MyTable
      Events:
        GetItems:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /items
            Method: GET
      # CodeDeploy 설정
      AutoPublishAlias: live
      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Alarms:
          - !Ref GetItemsAlarm
 
  CreateItemFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/createItem.handler
      CodeUri: .
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref MyTable
      Events:
        CreateItem:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /items
            Method: POST
 
  # DynamoDB 테이블
  MyTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: !Sub "${Environment}-items"
      PrimaryKey:
        Name: id
        Type: String
 
  # CloudWatch Alarm
  GetItemsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: GetItems function errors
      Namespace: AWS/Lambda
      MetricName: Errors
      Dimensions:
        - Name: FunctionName
          Value: !Ref GetItemsFunction
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanThreshold
 
# 출력
Outputs:
  ApiUrl:
    Description: API Gateway URL
    Value: !Sub "https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/${Environment}/"
 
  TableName:
    Description: DynamoDB Table Name
    Value: !Ref MyTable

프로젝트 구조

my-sam-project/
├── template.yaml           # SAM 템플릿
├── samconfig.toml          # 환경별 설정
├── package.json
├── src/
│   └── handlers/
│       ├── getItems.js     # GET /items
│       └── createItem.js   # POST /items
├── events/
│   ├── getItems.json       # 테스트 이벤트
│   └── createItem.json
└── tests/
    └── unit/
        └── handlers.test.js

핵심 요약

SAM CLI 명령어 요약

명령어용도
sam init프로젝트 초기화
sam build빌드
sam deploy배포 (CloudFormation)
sam sync빠른 동기화 (개발용)
sam sync --watch파일 변경 감지 + 자동 동기화
sam local invokeLambda 로컬 실행
sam local start-apiAPI Gateway 로컬 실행
sam local generate-event테스트 이벤트 생성
sam logsCloudWatch 로그 조회
sam delete스택 삭제

SAM 리소스 타입

SAM 타입생성되는 것
AWS::Serverless::FunctionLambda + IAM Role
AWS::Serverless::ApiAPI Gateway REST API
AWS::Serverless::HttpApiAPI Gateway HTTP API
AWS::Serverless::SimpleTableDynamoDB

배포 전략

전략설명
AllAtOnce즉시 전환
CanaryX% 먼저, 대기, 나머지
Linear일정 간격으로 X%씩

시험 포인트 체크리스트

  • SAM Transform: AWS::Serverless-2016-10-31
  • SAM은 CloudFormation의 확장 (모든 CF 기능 사용 가능)
  • sam sync --watch: 파일 변경 감지 + 자동 동기화
  • Policy Templates: S3ReadPolicy, DynamoDBCrudPolicy 등
  • AutoPublishAlias: 자동으로 버전 생성 + Alias 연결
  • DeploymentPreference: Canary, Linear, AllAtOnce
  • sam local start-api: API Gateway 로컬 에뮬레이션
  • sam local generate-event: 테스트 이벤트 생성
  • samconfig.toml: 환경별 설정 파일

TypeScript/React 개발자를 위한 SAM 활용:

프로젝트 초기화:

sam init --runtime nodejs18.x --app-template hello-world-typescript

개발 워크플로우:

# 1. 로컬에서 API 테스트
sam local start-api
 
# 2. 개발 중 자동 동기화
sam sync --watch --config-env dev
 
# 3. 프로덕션 배포
sam deploy --config-env prod

이 조합으로 빠르고 안전한 서버리스 개발을 할 수 있어요! 🙂