Layer 기능을 사용한 Lambda function을 로컬 환경에서 개발하면서 AWS SAM&CodeBuild에서 배포하는 경우

Layer 기능을 사용한 Lambda function을 로컬 환경에서 개발하면서, SAM&CodeBuild로 AWS상에 배포하면 지금까지를 해본 비망록.

1. 구성



디렉토리 구성(로컬)
project/
  ├ .git
  ├ functions/
  │  ├ lambda-payloads.json
  │  └ lambda_function.py
  ├ .gitignore
  ├ buildspec.yml
  ├ template.yaml
 --以下はRequestsライブラリ部分⇒ここがLambda Layerとしてuploadされている状態--
  ├ certifi/
  ├ certifi-2018.11.29.dist-info/
  ├ chardet/
  ├ chardet-3.0.4.dist-info/
  ├ idna/
  ├ idna-2.8.dist-info/
  ├ requests/
  ├ requests-2.21.0.dist-info/
  ├ urllib3/
  └ urllib3-1.24.1.dist-info/

2. 레이어 취급



고민한 것은,

· AWS에서 Requests 라이브러리를 Layer로 업로드하고 사용하고 싶습니다.
· 그러나 개발 단계에서는 로컬 환경에서 테스트하고 싶습니다.

라는 케이스.

Layer를 어떻게 다루면 좋은지 고민한 결과, 다음과 같이 하기로 했다.

・AWS상과 마찬가지로 import requests 할 수 있도록 requests 라이브러리용의 각 모듈을 배치(상기 구성하에서의 10 디렉토리)
· 해당 디렉토리를 gitignore

이것으로, 일단 AWS상/로컬로 차이가 없는 import 지정으로 통하면서, Lambda상에 쓸데없는 모듈을 올리지 않고 끝났다.

lambda_function.py
import boto3
import json
import datetime
import os
import requests

.gitignore
certifi*/
chardet*/
idna*/
requests*/
urllib3*/
functions/lambda-payloads.json

3. Lambda function 배포



Lambda function의 배포는 CodeBuild에서 AWS SAM을 사용하여 자동화.

①AWS SAM용 템플릿 생성



Properties에 필요한 설정을 채우고 template.yaml 파일을 만듭니다.
"Layers"에서 업로드 된 Layer의 ARN을 지정하면서 "Tracing"에서 X-Ray 추적을 활성화하고 있습니다.

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Create Lambda function by using AWS SAM.
Resources:
  UpdateItemFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: functions/lambda_function.lambda_handler
      Runtime: python3.6
      Role: 'arn:aws:iam::<Account_ID>:role/deploy_lambda_role'
      Timeout: 15
      Layers:
        - 'arn:aws:lambda:us-west-2:<Account_ID>:layer:requests:1'
      Tracing: Active
      Environment:
        Variables:
          URL: '<API Gateway Endpoint>'
      Description: ''
      MemorySize: ''

②CodeBuild용 buildspec.yaml 작성



CodeBuild에서는 다음의 흐름으로 Lambda function을 배포.

Ⅰ. SAM 템플릿에서 Lambda 코드를 패키징하여 S3에 업로드 (S3 버킷은 미리 생성)
Ⅱ. 업로드 대상 S3의 URI가 확장된 SAM 템플릿 출력
III. Ⅱ에서 출력된 SAM 템플릿을 사용하여 CloudFormation에서 Lambda function 배포

이 흐름을 실행시키기 위한 buildspec 파일을 이하와 같이 작성. (Ⅰ&Ⅱ가 build 단계, III가 post_build 단계)

buildspec.yaml
version: 0.2
phases:
  build:
    commands:
      - >-
        aws cloudformation package --template-file template.yaml --s3-bucket
        sam-repository --output-template-file packaged-template.yaml
  post_build:
    commands:
      - >-
        aws cloudformation deploy --template-file packaged-template.yaml
        --stack-name msa-lambda-stack --capabilities CAPABILITY_IAM
        --no-fail-on-empty-changeset

포인트는, aws cloudformation deploy시에 옵션 "--no-fail-on-empty-changeset"를 붙이는 것.
이것이 없으면 최초 배포 시 대상의 Change Set가 존재하지 않기 때문에 Status Code ≠ 0이 되어 배포가 실패해 버리지만, 옵션을 붙임으로써 Status Code = 0을 응답시킬 수 있다.

또 1점 조심해야 할 포인트가, 사용하는 Role에의 권한 부여.
특히 lambda, cloudformation에 대하여 상당히 많은 Action를 허용해야 했다.

deploy_lambda_role(일부 발췌)
{
    "Effect": "Allow",
    "Action": [
            "lambda:CreateFunction",
            "lambda:UpdateFunctionCode",
            "lambda:GetLayerVersion",
            "lambda:UpdateFunctionConfiguration",
            "cloudformation:CreateStack",
            "cloudformation:UpdateStack",
            "cloudformation:CreateChangeSet",
            "cloudformation:DescribeChangeSet",
            "cloudformation:ExecuteChangeSet",
            "cloudformation:GetTemplateSummary",
            "cloudformation:DescribeStacks"
        ],
    "Resource": "*"
}

※또한 aws cloudformation package 커멘드에서는, packaged-template.yaml가 이런 느낌으로 전개된다

packaged-template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Create Lambda function by using AWS SAM.
Resources:
  UpdateItemFunction:
    Properties:
      CodeUri: s3://<アップロード先S3のURI>
      Environment:
        Variables:
          URL: '<API Gateway Endpoint>'
      Handler: functions/lambda_function.lambda_handler
      Layers:
      - arn:aws:lambda:us-west-2:<Account_ID>:layer:requests:1
      Role: arn:aws:iam::<Account_ID>:role/deploy_lambda_role
      Runtime: python3.6
      Timeout: 15
      Tracing: Active
    Type: AWS::Serverless::Function
Transform: AWS::Serverless-2016-10-31

③CodeBuild 프로젝트 작성



CodeBuild에서는 단순히 buildspec대로 명령 실행시킬 뿐이므로 특필해야 할 점은 없다.

소스

리포지토리에 CodeCommit 지정


환경

aws cloudformation package & deploy 명령을 실행하기 때문에 Runtime은 Docker를 지정합니다.


Buildspec & Artifacts

Buildspec 파일에 Source 저장소에 배치된 buildspec.yaml을 지정합니다. Artifacts는 필요하지 않습니다.


이것으로 CodeBuild 프로젝트 작성은 완료.

④실행



작성한 Build 프로젝트를 실행하면, CFn 스택이 작성된 후, 무사 Lambda function이 배치된다.
그리고는 CodePipeline에서 CodeCommit과 연결하면 자동화도 OK.

4. 후기



Lambda의 배포도 여러 가지 방법이 있지만, 이것이 가장 심플한 생각이 들었습니다.

로컬 환경에서 레이어를 다루는 것은 확실히 정답이 아니라고 생각하지만 좋은 방법을 생각하지 않습니다 ...
이거야 하는 방법이 있으면 가르쳐 주시면 다행입니다.

좋은 웹페이지 즐겨찾기