์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ™œ์„ฑํ™” ํ•ด์ฃผ์„ธ์š”

AWS Lambda with SAM

AWS SAM์œผ๋กœ ์„œ๋ฒ„๋ฆฌ์Šค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ด€๋ฆฌํ•˜๊ธฐ

 ·  โ˜• 5 min read

๋“ค์–ด๊ฐ€๋ฉฐ


ย ย ย ์„œ๋น„์Šค ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด Serverless๋กœ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธด๋‹ค. AWS๋ฅผ ์“ฐ๊ณ ์žˆ๋‹ค๋ฉด Lambda ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋˜๋Š”๋ฐ, ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์—๋Š” ์ฝ˜์†”๋กœ ์ฝ”๋“œ๋ฅผ ์ง์ ‘์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์—…๋กœ๋“œ ํ•ด๋„ ๋˜์ง€๋งŒ ๊ฒฐ๊ตญ CI/CD ๊ตฌ์„ฑ์ด ์š”๊ตฌ๋œ๋‹ค. Severless ๋ฐฐํฌ ๋ฐ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๋„๊ตฌ๋“ค์€ ์ด๋ฏธ ๋งŽ์ด ์กด์žฌํ•œ๋‹ค(Serverless, AWS SAM, Zappa(Python), Chalice(Python)) ๊ทธ ์ค‘์—์„œ๋„ AWS SAM์„ ํ™œ์šฉํ•˜์—ฌ AWS Lambda์˜ ๋ฐฐํฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค. ๋‹จ์ˆœํžˆ CI/CD ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋กœ์ปฌ ํ…Œ์ŠคํŒ…, IAC ์˜ ํšจ๊ณผ๊นŒ์ง€ ์–ป์„์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋ฒˆ๊ธ€์„ ํ†ตํ•ด์„œ SAM์„ ํ™œ์šฉํ•˜์—ฌ AWS Lambda๋ฅผ ๊ด€๋ฆฌํ•œ ๋ฐฉ๋ฒ•์„ ๊ฐ„๋‹จํžˆ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค.

AWS SAM ๊ตฌ์กฐ


ย ย ย AWS SAM์€ AWS ์ข…์†์ ์ด๊ธด ํ•˜์ง€๋งŒ, ํ˜„์žฌ ํšŒ์‚ฌ์—์„œ๋Š” AWS Cloud๋ฅผ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ , ์œ„์— ์–ธ๊ธ‰ํ•œ๋Œ€๋กœ local testing๊ณผ ์ธํ”„๋ผ ๊ด€๋ฆฌ๊นŒ์ง€ ๊ด€๋ฆฌํ• ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—(AWS CloudFormation ๋ฆฌ์†Œ์Šค๋„ ํฌํ•จ๊ฐ€๋Šฅํ•˜๋‹ค(๋งํฌ ์ฐธ๊ณ ), AWS SAM์„ ์ฑ„ํƒํ•˜์˜€๋‹ค. ์„ธํŒ…์ด๋‚˜ ๊ตฌ์„ฑ์€ aws ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค. ํ˜„์žฌ ์‚ฌ์šฉ์ค‘์ธ SAM ๊ตฌ์กฐ๋ฅผ ๊ฐ„์†Œํ™”ํ•ด์„œ ๋‚˜ํƒ€๋‚ด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ tree

โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ __init__.py
โ”œโ”€โ”€ common_layer
โ”‚   โ”œโ”€โ”€ Makefile
โ”‚   โ”œโ”€โ”€ python
โ”‚   โ””โ”€โ”€ requirements.txt
โ”œโ”€โ”€ events
โ”‚   โ””โ”€โ”€ event.json
โ”œโ”€โ”€ lambda_function1
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ main.py
โ”‚   โ”œโ”€โ”€ src
โ”‚   โ””โ”€โ”€ test_main.py
โ”œโ”€โ”€ lambda_function2
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ main.py
โ”‚   โ”œโ”€โ”€ src
โ”‚   โ””โ”€โ”€ test_main.py
โ”œโ”€โ”€ mypy.ini
โ”œโ”€โ”€ poetry.lock
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ samconfig.toml
โ”œโ”€โ”€ template.yaml
โ””โ”€โ”€ tests

ย ย ย ์ฃผ์š” ํŒŒ์ผ๋“ค์„ ์ •๋ฆฌํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • common_layer/: Lambda Layer๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ Makefile ๋ฐ python dependency
  • lambda_function1/, lambda_function2/: Lambda ์†Œ์Šค
  • samconfig.toml: ๋ฐฐํฌ์‹œ ์ฐธ์กฐํ•  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ •์˜
  • template.yaml: SAM ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ template์„ ์ •์˜
    ย ย ย common_layer์™€ lambda_function ํด๋”๋Š” ์˜ˆ์ œ์„ค๋ช…์„ ์œ„ํ•ด ์ง์ ‘ ์ถ”๊ฐ€ํ•œ ํด๋”์ด๋ฉฐ, samconfig ์™€ template ํŒŒ์ผ์€ sam application ์ดˆ๊ธฐํ™”์‹œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

ํ™˜๊ฒฝ๊ด€๋ฆฌ(Prod, Dev)


ย ย ย samcofing.toml์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ template.yaml์— ํ™œ์šฉํ•˜๋ฉด ๋ฐฐํฌํ™˜๊ฒฝ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋ฐฐํฌ, ๊ด€๋ฆฌํ• ์ˆ˜ ์žˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ Lambda function 2๊ฐœ๋ฅผ API Gateway 1๊ฐœ๋กœ ์„œ๋น™ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์˜ˆ์ œ๋กœ ๋งŒ๋“ค์–ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description:
  '
  SAM example
  '

Parameters:
  Env:
    Type: String
    Description: Which environment do you want to deploy to? (dev, prod)
    AllowedValues:
      - dev
      - prod
    Default: dev
  SubnetA:
    Type: String
  SubnetB:
    Type: String


Resources:
  LambdaFunction1:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "Lambda-${Env}-Lambda-Function-1"
      CodeUri: lambda_function1
      Handler: main.handler
      Runtime: python3.9
      Architectures:
      - x86_64
      Events:
        LambdaFunction1:
          Type: Api
          Properties:
            Path: /first/{proxy+}
            Method: ANY
            RestApiId: !Ref API
      VpcConfig:
        SubnetIds:
          - !Sub ${SubnetA}
          - !Sub ${SubnetB}
    Metadata:
      SamResourceId: LambdaFunction1

  LambdaFunction2:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "Lambda-${Env}-Lambda-Function-2"
      CodeUri: lambda_function2
      Handler: main.handler
      Runtime: python3.9
      Architectures:
      - x86_64
      Events:
        LambdaFunction2:
          Type: Api
          Properties:
            Path: /second/{proxy+}
            Method: ANY
            RestApiId: !Ref API
      VpcConfig:
        SubnetIds:
          - !Sub ${SubnetA}
          - !Sub ${SubnetB}
        SecurityGroupIds:
          - !Sub ${securityGroupId}
    Metadata:
        SamResourceId: LambdaFunction2

  API:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Sub ${Env}
  • line 9~20 : template์—์„œ ์‚ฌ์šฉํ•  parmeter ์ •์˜, samconfig.toml์„ ํ†ตํ•ด ๊ฐ’์„ ์ฃผ์ž…ํ•จ.
  • line 24~45 : lambda_function1 ์ •์˜, parameter ๊ฐ’์„ ํ™œ์šฉํ•˜์—ฌ Lambda ํ•จ์ˆ˜๋ช…๊ณผ subnet ํ™˜๊ฒฝ๋ถ„๋ฆฌ.
  • line 33~39 : lambda_function1 ์˜ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ ์ •์˜, ๋‹ค์–‘ํ•œ ๋ฆฌ์†Œ์Šค์ง€์ •(S3, SNS Event…)์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์˜ˆ์ œ์—์„œ๋Š” API Gateway์˜ ’/first’ path๋ฅผ ํ†ตํ•ด ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ๊ฒฝ์šฐ lambda_function1์ด ํŠธ๋ฆฌ๊ฑฐ ๋œ๋‹ค.
  • line 47~70 : lambda_function2 ์ •์˜, parameter ๊ฐ’์„ ํ™œ์šฉํ•˜์—ฌ Lambda ํ•จ์ˆ˜๋ช…๊ณผ subnet ํ™˜๊ฒฝ๋ถ„๋ฆฌ. API Gateway์˜ ’/second’ path๋ฅผ ํ†ตํ•ด ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ๊ฒฝ์šฐ lambda_function2์ด ํŠธ๋ฆฌ๊ฑฐ ๋œ๋‹ค.
  • line 72~75 : Lambda๋ฅผ ์„œ๋น™ํ•˜๊ธฐ์œ„ํ•œ API GW ์ •์˜
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# samconfig.toml
version = 0.1
[default]
[default.deploy]
[dev.deploy.parameters]
stack_name = "CF-DEV-SAM-EXAMPLE-APP"
region = "ap-northeast-2"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
parameter_overrides = """Env=\"stage\" \
SubnetA=\"์‚ฌ์šฉ์ค‘์ธ dev subnet id\" \
SubnetB=\"์‚ฌ์šฉ์ค‘์ธ dev subnet id\""""

[prod.deploy.parameters]
stack_name = "CF-PROD-SAM-EXAMPLE-APP"
region = "ap-northeast-2"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
parameter_overrides = """Env=\"prod\" \
SubnetA=\"์‚ฌ์šฉ์ค‘์ธ prod subnet id\" \
SubnetB=\"์‚ฌ์šฉ์ค‘์ธ prod subnet id\""""
  • line 5~12 : SAM config dev deploy section, stack_name์€ SAM ๋ฐฐํฌ์‹œ ์‚ฌ์šฉ๋˜๋Š” Cloudformation๋ช…์„ ์ •์˜ํ•œ๊ฒƒ์ด๊ณ  parameter_overrides ์˜ต์…˜์„ ํ†ตํ•ด SAM template์— ์ „๋‹ฌํ•  parameter๋ฅผ ์ •์˜ํ•œ๋‹ค.
  • line 14~21 : SAM config production deploy section
  • ์ด๋ ‡๊ฒŒ ์ •์˜ํ•œ deploy option์€ ๋ฐฐํฌ์‹œ --config-env ์˜ต์…˜์œผ๋กœ ์ง€์ •ํ• ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐฐํฌ ์˜ˆ์‹œ
    1
    2
    
    sam deploy --config-env dev   # dev
    sam deploy --config-env prod  # prod
    

Layer ๊ด€๋ฆฌ


ย ย ย Labmda์˜ ๊ฒฝ์šฐ ์ฝ”๋“œ ์—…๋กœ๋“œ ์‚ฌ์ด์ฆˆ ํฌ๊ธฐ์— ์ œํ•œ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์™ธ๋ถ€ํŒจํ‚ค์ง€๋‚˜ ๊ณต์šฉ ๋ชจ๋“ˆ์˜๊ฒฝ์šฐ Lambda Layer๋กœ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค. SAM์—์„œ๋„ Lambda Layer๋ฅผ bulidํ•˜์—ฌ ๋ฐฐํฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ž์„ธํ•œ ๋ฐฉ๋ฒ•์€ ๋งํฌ๋ฅผ ํ™•์ธํ•˜๋ฉด ๋˜๋ฉฐ, ์ตœ์ข…์ ์ธ SAM template์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# template.yaml

# ...์ƒ๋žต

Resources:
  # Layer ์ถ”๊ฐ€
  CommonLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      ContentUri: common_layer
      CompatibleRuntimes:
        - python3.9
    Metadata:
      BuildMethod: makefile

  LambdaFunction1:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "Lambda-${Env}-Lambda-Function-1"
      CodeUri: lambda_function1
      Handler: main.handler
      Runtime: python3.9
      Layers: 
        - !Ref CommonLayer  # Layer property ์ถ”๊ฐ€
  
# ... ์ƒ๋žต

Local test


ย ย ย SAM์„ ํ™œ์šฉํ•˜์—ฌ local์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ์˜ต์…˜์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์žˆ๋Š”๋ฐ, ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์˜ต์…˜ ๋‘๊ฐ€์ง€๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • sam local start-api : ๋กœ์ปฌ์—์„œ API Gateway๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์˜ต์…˜, ๋กœ์ปฌ ์„œ๋ฒ„์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๋‹ค
  • sam local invoke : ๋กœ์ปฌ์—์„œ Lambda ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์˜ต์…˜, API Gateway๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ event๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ ํ™œ์šฉํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ๋“ค์–ด AWS SNS์˜ notification์ด ๋ฐœ์ƒ๋˜๋ฉด Lambda ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
      1
      2
      3
      
      sam local generate-event --help  # --help๋กœ event list ํ™•์ธ ๊ฐ€๋Šฅ
      sam local generate-event sns notification > events/sns-event.json # sns-event.json ์ƒ์„ฑ
      sam local invoke TestFunction -e events/sns-event.json # TestFunction ์‹คํ–‰
      

๋งˆ์น˜๋ฉฐ


ย ย ย ํ˜„์žฌ ํšŒ์‚ฌ์—์„œ SAM์„ ์‚ฌ์šฉํ•˜์—ฌ 10์—ฌ๊ฐœ์˜ Lambda์™€ ๊ด€๋ จ ๋ฆฌ์†Œ์Šค๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค. ๊ธฐ์กด์˜ ๊ฒฝ์šฐ Lambda์˜ ํ˜•์ƒ๊ด€๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ค‘๊ตฌ๋‚œ๋ฐฉ์œผ๋กœ ๋ฐฐํฌ๋˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ์œ„์™€ ๊ฐ™์ด SAM์œผ๋กœ ๊ตฌ์„ฑํ•œ ๋’ค๋กœ๋Š” ํ•˜๋‚˜์˜ Repository ์—์„œ Lambda๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๋ฐฐํฌ ์ž๋™ํ™”๊นŒ์ง€ ๊ตฌ์ถ•ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋˜ํ•œ samconfig๋ฅผ ํ†ตํ•ด ํ™˜๊ฒฝ๊ตฌ์ถ•์„ ์‰ฝ๊ฒŒ ๋ถ„๋ฆฌ ํ• ์ˆ˜์žˆ๊ฒŒ ๋˜์–ด ํ…Œ์ŠคํŠธ๋‚˜ PoC๋ฅผ ์œ„ํ•œ ๊ตฌ์ถ•๋„ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜์—ˆ๋‹ค.


shin alli
๊ธ€์“ด์ด
shin alli
Backend ๊ฐœ๋ฐœ์ž (Python, Django, AWS)