이 연재글은 AWS 람다(lambda) 실습의 9번째 글입니다.

aws lambda 함수는 대부분 한 가지의 목적을 달성한 다음 종료되는 함수입니다. 일반적인 서버처럼 여러 가지 요구조건을 수용하지 않기 때문에 lambda 함수는 계속 개수가 늘어나게 됩니다. 여기서 문제는 lambda 함수를 배포할 때 함수에서 필요로 하는 모듈들이 전부 압축되어 업로드된다는 점입니다. 이로 인해 개발한 소스파일 용량은 얼마 안되는데도 불구하고 배포 된 람다 용량을 보면 수 megabyte에서 수십 megabyte 인 것을 확인할 수 있습니다.

  • 업로드 용량이 늘어난다는 것은 용량 낭비가 발생한다는 것도 있지만 배포 시간이 늘어난다는 단점이 있습니다.
  • lambda에서 공통으로 사용하는 모듈에 변경사항이 발생할 경우 관련된 lambda를 모두 다시 배포해야 하는 이슈가 발생합니다.

Aws에서는 이러한 단점을 극복하기 위해 Layer라는 개념을 도입했으며 Layer는 모듈의 집합으로서 공통으로 사용하는 모듈을 묶어 Lambda함수와는 별도로 배포하고 Lambda함수에서 include 하여 사용할 수 있습니다.

Serverless framework로 Layer 생성하기

Lambda Layer는 직접 module을 압축하여 aws console을 통해 업로드할 수 있습니다. 하지만 실습에서는 serverless framework를 이용하여 layer를 생성하고 배포해 보겠습니다.

Lambda Layer에 대한 더 자세한 사항은 다음 링크 내용을 참고하시면 됩니다.

https://www.serverless.com/framework/docs/providers/aws/guide/layers/

serverless create 명령으로 lambda function을 생성합니다. Layer로만 사용할 것이므로 handler.js는 삭제합니다.

# sls create --template aws-nodejs --path [생성할 디렉터리명] --name [서비스이름]
$ sls create --template aws-nodejs --path node-data-stream-utils --name node-data-stream-utils
$ ls
$ handler.js serverless.yml
$ rm handler.js

module을 담을 디렉터리 하나를 생성합니다. 여기서는 node-utils로 생성합니다. node-utils로 이동하여 npm i 명령으로 공통으로 사용할 모듈을 install 합니다.

$ mkdir node-utils
$ cd node-utils
$ npm i aws-sdk
$ npm i mysql

serverless.yml을 다음과 같이 Layer 형식으로 수정합니다. path에는 위에서 생성한 node-utils로 설정합니다.

service: node-data-stream-utils
frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-2

layers:
  NodeDataStreamUtils:
    path: node-utils
    description: "Node Data Stream Utils Dependencies"
    compatibleRuntimes:
      - nodejs12.x

여기까지 만들어진 디렉터리 구조는 아래와 같습니다.

 node-data-stream-utils
    ├── node-utils
    │   ├── node_modules
    │   ├── package-lock.json
    │   └── package.json
    └── serverless.yml

이제 serverless deploy 명령으로 aws에 배포합니다. 참고로 배포할 때마다 layer의 버전이 올라갑니다. 실습에서는 3번 업로드하여 버전이 3입니다.

$ sls deploy

Lambda 함수에 Layer 적용

lambda함수의 serverless.yml을 수정하여 Layer를 적용합니다. 적용해야 할 부분은 총 세부분이며 소스에 주석으로 표시하였습니다.

service: lambda-auroradb-converter
frameworkVersion: '2'

# 1. 람다 배포시 package에서 mode_module 배포 제외
package:
  exclude:
    - node_modules/**

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-2
  environment:
    # 2. 환경변수에 NODE_PATH 설정
    NODE_PATH: "./:/opt/node_modules"

functions:
  main:
    handler: handler.main
    # 3. 람다 함수에 layer arn 설정
    layers:
      - arn:aws:lambda:ap-northeast-2:593352196761:layer:NodeDataStreamUtils:3

람다 함수를 배포하고 aws console에서 확인하면 Lambda 함수의 용량이 크게 줄어든것을 확인할 수 있습니다. ( 11.7MB => 13.8kB )

Designer 화면에서는 Layer가 적용된 것을 확인할 수 있습니다.

최신 버전의 Layer를 사용

lambda layer 적용시 arn에는 버전이 명시되는것을 확인할 수 있습니다. 즉 layer가 업데이트되어 버전업이 되었다 해도 기존 lambda 함수에는 변경 내역이 적용되지 않습니다. 최신 버전의 layer를 보도록 처리하려면 아래 plugin을 사용하면 됩니다.

https://github.com/mooyoul/serverless-latest-layer-version

사용하고자 하는 lambda함수에서 plugin을 설치합니다.

$ npm i serverless-latest-layer-version --save-dev

serverless.yml 내용을 아래와 같이 수정합니다.
버전을 3->lastest로 변경하고 설치한 plugin을 적용합니다. 이후 배포 시에는 plugin에 의해 버전이 최신 버전으로 자동으로 변경되어 배포됩니다.

service: lambda-auroradb-converter
frameworkVersion: '2'

package:
  exclude:
    - node_modules/**

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-2
  environment:
    NODE_PATH: "./:/opt/node_modules"

functions:
  main:
    handler: handler.main
    # 1. 버전을 latest로 수정
    layers:
      - arn:aws:lambda:ap-northeast-2:593352196761:layer:NodeDataStreamUtils:latest

# 2. plugin 적용
plugins:
  - serverless-latest-layer-version
연재글 이동[이전글] aws lambda 개발하기(8) – Asynchronous Tasks by SQS(Simple Queue Service)