Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

Apex로 실제 Lambda 함수 작성하기

며칠 전에 Apex를 소개했는데 이 글에서 기본적인 사용방법을 다루기는 했지만, 도구의 사용방법과 이를 이용해서 실제로 프로젝트를 진행하는 것은 다른 얘기다. 사용법을 익히고 나서도 실제로 뭔가 만들려면 고민되는 문제가 겪게 되는 문제가 있기 마련이다.

nodejs-ko에서 Node.js 공식블로그의 글을 번역하고 있는데 새로운 글이 올라오면 트위터로 공지하고 있다. 기존에 사용하던 봇이 동작하지 않아서 최근에는 계속 수동으로 올리다가 Lambda에 올리기에 적당해 보여서 새로운 글이 올라오면 트윗으로 올려주는 봇을 작성했다. 기능상으로 아주 간단하지만, 운영까지 신경 쓰고 싶지는 않았기에 로직만 작성하면 신경 안 써도 되는 Lambda에 올리는 것이 적당해 보였다.

이 글에서는 nodejs-ko에 새로운 글이 올라오면 트위터로 올려주는 nodejs-ko-botApex로 작성하면서 고민한 결과를 정리한다.

프로젝트 구성

작성할 함수명을 tweet이라고 했을 때 아주 기본적인 폴더 구조는 다음과 같다.

├── functions
│   └── tweet
│       ├── function.json
│       └── index.js
└── project.json

지금은 트윗을 올려주는 함수만 있지만 차후 더 필요한 부분이 있으면 여기에 계속 추가할 수 있도록 project.json에는 기본 설정만 넣고 함수에서 필요한 설정(timeout 이나 환경변수 등)은 function.json에 넣었다. index.js에는 실제 함수 로직이 들어갈 것이다.

지난번 글에서 본 Hello World 함수가 아니라면 당연히 npm 모듈이 필요하므로 package.json으로 의존성을 관리해야 한다. 그러면 다음과 같은 구조가 된다.

├── functions
│   └── tweet
│       ├── function.json
│       ├── index.js
│       ├── node_modules/
│       └── package.json
└── project.json

이런 모양이 되는 이유는 당연히 함수마다 사용하는 모듈이 다르므로 함수마다 의존성을 관리할 수 있어야 하고 tweet폴더가 zip 파일로 압축되어서 Lambda에 업로드되므로 설치한 의존성 모듈이 있는 node_modules 폴더도 tweet 폴더 아래에 있어야 한다. 실제로 어떻게 빌드 파일을 만드는지 확인해 볼 수 있도록 apex에서는 build 명령어를 제공하고 있다.

$ apex build tweet > out.zip

위 명령어를 실행하면 out.zip 파일이 생성되고 이 파일의 압축을 풀면 다음과 같은 구조로 되어 있다.

├── .env.json
├── _apex_index.js
├── index.js
└── node_modules
    └── ...

project.jsonfunction.json의 설정을 합쳐서 .env.json를 만들어 주고 실행 파일인 _apex_index.js를 넣어준다. 그리고 작성한 .js 파일과 node_modules폴더가 포함되어 있다. 이 압축 파일이 그대로 올라가고 AWS Lambda 내에서도 이를 그대로 사용하게 된다. 그래서 필요한 모듈을 node_modules에 다 설치해야 하고 JavaScript로만 작성되지 않고 gyp로 빌드가 필요한 모듈은 AWS에서 사용하는 Amazon Linux에 맞게 빌드가 되어 있지 않으면 동작하지 않는다.

빌드를 어떻게 되는지 이해하고 나니 프로젝트 구성에 대한 몇 가지 고민이 생겼다.

  1. package.json의 위치: 의존성 모듈을 관리하려면 함수 폴더 내에 package.json이 있는 게 맞지만 이럴 때 함수가 여러 개 생기면 폴더마다 들어가서 npm install을 실행해주어야 하므로 귀찮아진다.
  2. 개발용 의존성의 관리: 위 구조는 예시로 아주 간단한 파일만 넣었지만 실제로 개발하면 테스트 코드도 작성해야 하므로 mochachai같은 devDependencies를 설치해야 한다. 함수를 여러 개 만들더라도 이 devDependencies는 프로젝트 공통일 가능성이 크고 배포할 필요는 없으므로 배포될 node_modules내에서는 빼주어야 한다.

이 문제를 해결하려고 구성한 폴더 구조는 다음과 같다. 요즘은 ES2015로 코드를 작성하고 Babel로 트랜스파일하는 게 일반적이지만 Node.js v4에서도 어느 정도 ES2015의 기능을 사용할 수 있고 꼭 필요하지 않으면 트랜스파일을 사용하지 않기 때문에 Webpack등의 사용을 고려하지 않은 구조이다.

├── functions
│   └── tweet
│       ├── function.json
│       ├── index.js
│       ├── node_modules/
│       └── package.json
├── node_modules/
├── package.json
└── project.json

package.json를 프로젝트 루트에도 넣고 함수 폴더 안에도 넣었다. 프로젝트 루트에 있는 package.json에서는 프로젝트 전체에서 공통으로 사용하지만 배포할 필요는 없는 의존성 모듈(주로 devDependencies)을 관리하고 함수 폴더 안에 있는 package.json에서는 Lambda에서 사용할 로직에 필요한 모듈만 관리한다. 그리고 루트의 package.json에서 npm-scriptspostinstall 훅을 다음과 같이 추가했다.

"scripts": {
  "postinstall": "find ./functions/* -name package.json -maxdepth 1 -execdir npm install \\;"
}

postinstallnpm install이 완료되면 실행되는 스크립트로 여기서 functions폴더 하위에 package.json 파일이 있으면 npm install을 실행하도록 추가했다. 이러면 루트에서만 npm install을 하면 각 함수 폴더에서도 npm install이 실행되어 위의 구조처럼 node_modules 폴더가 루트 말고 각 함수에도 생기게 된다. 이제 apex deploy를 하면 필요한 모듈만 배포할 수 있게 되었다.

유닛 테스트

간단한 함수가 아니라면 당연히 테스트를 작성해야 한다. apex invoke로 동작을 확인해 볼 수 있지만, 로직이 복잡해 질수록 매번 Lambda를 직접 실행해서 테스트하는 것 불편하기도 하고 좋은 방법도 아니다. 보통 Node.js 코드를 작성할 때와 마찬가지로 모듈화해서 모듈별로 테스트를 작성하는 게 좋다. 이번에 작성하던 기능은 nodejs-ko 블로그에 새로운 피드가 올라오면 이를 트위터로 보내주는 것이다.

그러면 다음의 기능이 필요하다.

  1. RSS 피드를 읽어온다.
  2. 새로운 글이 있는지 확인한다.
  3. 새로운 글을 트위터에 트윗으로 올린다.

여기서 새로운 글을 확인하려면 기존에 트윗한 글이 어떤 글인지 알고 있어야 하는데 Lambda는 함수가 호출될 때마다 새로 서버가 실행되므로 데이터를 유지할 방법이 없다. 이런 경우에는 어딘가에 데이터를 저장해야 하는데 데이터베이스를 사용할 정도는 아니므로 S3를 이용해서 파일로 저장했다. 다시 정리하면

  1. RSS 피드를 읽어온다.(feed.js)
  2. S3에서 기존에 트윗한 글 목록을 가져온다.(store.js)
  3. RSS 피드에서 기존에 트윗하지 않은 글을 찾는다.(feed.js)
  4. 트윗하지 않은 글이 있으면 이를 트윗한다.(tweet.js)
  5. 트윗한 새 글 목록을 S3에 다시 저장한다.(store.js)

대충 이 정도다. 이는 개별적으로 따로 기능을 구현하고 테스트를 할 수 있다.

├── functions
│   └── tweet
│       ├── feed.js
│       ├── function.json
│       ├── index.js
│       ├── node_modules/
│       ├── package.json
│       ├── store.js
│       └── tweet.js
├── node_modules/
├── package.json
├── project.json
└── test
    ├── feed.spec.js
    ├── store.spec.js
    └── tweet.spec.js

테스트 폴더는 배포할 필요가 없으므로 프로젝트 루트에 넣었다. 상대 경로로 대상 파일을 가져오면 테스트하는 데 문제가 없기 때문이다. 각 기능의 테스트가 문제없다면 기능이 모두 동작하는 것이므로 index.js에서는 각 기능을 엮어주는 정도만 작성하면 굳이 테스트를 작성하지 않고도 동작을 어느 정도 보장할 수 있고 전체 기능을 Lambda에서 한두 번 테스트해주면 된다.

테스트를 작성할 때 고민한 점은 일반적인 테스트에서는 기본 환경은 development로 두고 프로덕션에서는 NODE_ENVproduction이므로 이 관례에 따라서 동작하게 하는 게 일반적이지만 Lambda에서는 NODE_ENV 환경변수가 없으므로 이를 활용할 수가 없다.(설정하면 되긴 하지만) 나 같은 경우는 설정값에 기본값을 테스트 설정값으로 두고 실제 Lambda에서 돌아갈 때는 function.json에서 환경변수로 값을 전달하도록 해서 테스트와 다르게 동작하도록 했다. Apex에서 프로파일 별로 환경을 지정할 수 있지만 그 정도로 할 기능은 아니라서 간단하게 처리했다.

"scripts": {
  "test": "./node_modules/mocha/bin/mocha -t 10000 test"
},

프로젝트 루트에 있는 package.json에서 test 스크립트를 추가해서 npm test로 전체 테스트를 확인해 볼 수 있도록 했다.

apex infra

이렇게 작성한 Lambda 함수를 apex deploy로 배포할 수 있다. 이 기능 같은 경우는 외부에서 호출하는 기능이 아니라 배치로 동작하면서 새로운 글이 올라오면 트윗으로 올려주는 기능이면 충분하므로 30분에 한 번 정도만 실행되면 된다. AWS Lambda에서 배치는 CloudWatch를 이용해서 일정 시간마다 Lambda 함수를 호출하게 할 수 있다. 이를 위해서 AWS 웹 콘솔에서 설정할 수도 있지만 apex로 터미널에서 다 작업을 하고 있는데 트리거는 웹에서 설정한다는 게 맞지 않고 Lambda 같은 기능일수록 어떻게 설정되었는지 확인하기 어려우므로 코드로 설정을 자동화해놓는 게 좋다고 생각한다.(AWS에 의존성이 있는 설정임에도...)

apex에서는 Lambda 외의 AWS 리소스를 설정하는 기능으로 HashiCorp에서 만든 Terraform을 지원하고 있다. apex infra라는 명령어를 사용하고 있지만, 이는 실제로 terraform을 대신 실행해 주는 별칭일 뿐이다. 인프라 관련 설정은 모두 infrastructure폴더 아래에 모이는데 이 아래 프로덕션, 스테이지 등 환경별로 만들 수도 있는데 여기서는 간단하게 프로덕션 환경 하나만 만들었다.

├── functions
│   └── tweet
├── infrastructure
│   ├── main.tf
│   └── variables.tf
└── test

구조를 간략화하면 위와 같은 형태가 된다. 여기서 apex infra plan을 실행하면 실제로는 cd infrastructure && terraform plan과 똑같다고 보면 된다. 그래서 로컬에 Terraform이 설치되어 있어야 한다. Terraform이 헷갈리면 직접 infrastructure폴더 아래로 들어가서 terraform을 직접 사용해도 된다.

나도 아직 Terrafrom을 자세히 알지는 못하고 이번 기능 구현을 위한 간단한 설정만 찾은 상태이다.

$ apex list --tfvars
apex_function_tweet="arn:aws:lambda:ap-northeast-1:410655858509:function:nodejs-ko-bot_tweet"

apex에서 필요한 변수를 Terraform에 자동으로 넘겨주는데 여기서 변수명을 알고 싶다면 apex list --tfvars을 실행하면 된다. 이는 배포한 Lambda 함수(여기서는 tweet)의 ARN이 apex_function_함수명의 이름으로 전달이 된다. Lambda 함수의 ARN이므로 함수를 배포해야 이 값이 출력된다. 이 변수를 Terraform에서 사용하려면 variables.tf을 만들어야 한다.

variable "aws_region" {}
variable "apex_function_tweet" {}

앞에서 출력된 apex_function_tweet외에 AWS 리전을 의미하는 aws_region도 변수로 내보내는데 (헷갈리게) 위의 --tfvars에서는 출력되지 않는다. 이 변수들을 Terraform에 전달하려면 위와 같이 빈 값인 {}로 정의하면 된다. 실제 값은 apex infra를 실행할 때 할당된다.

resource "aws_cloudwatch_event_rule" "every_thirty_minutes" {
    name = "every-thirty-minutes"
    description = "Fires every thirty minutes"
    schedule_expression = "rate(30 minutes)"
}

resource "aws_cloudwatch_event_target" "tweet_every_thirty_minutes" {
    rule = "${aws_cloudwatch_event_rule.every_thirty_minutes.name}"
    arn = "${var.apex_function_tweet}"
}

resource "aws_lambda_permission" "allow_cloudwatch_to_call_tweet" {
    statement_id = "AllowExecutionFromCloudWatch"
    action = "lambda:InvokeFunction"
    function_name = "${var.apex_function_tweet}"
    principal = "events.amazonaws.com"
    source_arn = "${aws_cloudwatch_event_rule.every_thirty_minutes.arn}"
}

위 파일은 main.tf이다. 여기서 CloudWatch로 30분마다 Lambda 함수를 호출할 수 있게 정의한 것이다. every_thirty_minutes라는 이름으로 30분마다 호출되는 CloudWatch 규칙을 만들고 tweet_every_thirty_minutes라는 이름으로 CloudWatch의 타겟을 정의한다. 이때 apex에서 전달받은 변수를 정의하기 위해 ${var.apex_function_tweet}로 정의했다. 그리고 정의한 규칙에서 대상 Lambda 함수를 호출할 수 있도록 allow_cloudwatch_to_call_tweet라는 권한을 설정하면 된다. 이렇게 설정하면 30분마다 CloudWatch에서 배포함 tweet Lambda 함수를 호출하게 설정할 수 있다.

이제 실제로 사용해 보자.

$ apex infra plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_cloudwatch_event_rule.every_thirty_minutes
    arn:                 "<computed>"
    description:         "Fires every thirty minutes"
    is_enabled:          "true"
    name:                "every-thirty-minutes"
    schedule_expression: "rate(30 minutes)"

+ aws_cloudwatch_event_target.tweet_every_thirty_minutes
    arn:       "arn:aws:lambda:ap-northeast-1:410655858509:function:hello-world_tweet"
    rule:      "every-thirty-minutes"
    target_id: "<computed>"

+ aws_lambda_permission.allow_cloudwatch_to_call_tweet
    action:        "lambda:InvokeFunction"
    function_name: "arn:aws:lambda:ap-northeast-1:410655858509:function:hello-world_tweet"
    principal:     "events.amazonaws.com"
    source_arn:    "${aws_cloudwatch_event_rule.every_thirty_minutes.arn}"
    statement_id:  "AllowExecutionFromCloudWatch"


Plan: 3 to add, 0 to change, 0 to destroy.

apex infra plan 즉, terramform plan은 설정을 가상으로 AWS에 적용해 보고 어떤 변화가 생기는지를 적용 전에 확인할 수 있는 기능이다. 이를 실행하면 위처럼 3개의 규칙(규칙, 타겟, 권한)이 추가 되는 것을 볼 수 있고 마지막 Plan에서 3개가 추가된다고 알려주는 것을 볼 수 있다.

plan으로 확인할 설정에 문제가 없다면 apex infra apply(terraform apply)를 실행하면 실제로 AWS에 적용된다.

$ apex infra apply
aws_cloudwatch_event_rule.every_thirty_minutes_test: Creating...
  arn:                 "" => "<computed>"
  description:         "" => "Fires every thirty minutes"
  is_enabled:          "" => "true"
  name:                "" => "every-thirty-minutes"
  schedule_expression: "" => "rate(30 minutes)"
aws_cloudwatch_event_rule.every_thirty_minutes_test: Creation complete
aws_cloudwatch_event_target.tweet_every_thirty_minutes_test: Creating...
  arn:       "" => "arn:aws:lambda:ap-northeast-1:410655858509:function:hello-world_tweet"
  rule:      "" => "every-thirty-minutes"
  target_id: "" => "<computed>"
aws_lambda_permission.allow_cloudwatch_to_call_tweet_test: Creating...
  action:        "" => "lambda:InvokeFunction"
  function_name: "" => "arn:aws:lambda:ap-northeast-1:410655858509:function:hello-world_tweet"
  principal:     "" => "events.amazonaws.com"
  source_arn:    "" => "arn:aws:events:ap-northeast-1:410655858509:rule/every-thirty-minutes"
  statement_id:  "" => "AllowExecutionFromCloudWatch"
aws_cloudwatch_event_target.tweet_every_thirty_minutes_test: Creation complete
aws_lambda_permission.allow_cloudwatch_to_call_tweet_test: Creation complete

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

이제 인프라 설정까지 코드로 자동화가 되었다.(S3 버킷 설정 등은 빠졌지만...) 이제 문제가 생기거나 다른 계정 혹은 다른 VPC에서도 언제든지 똑같은 환경으로 Lambda 설정을 배포할 수 있게 되었다. terraform으로 인프라를 적용하고 나면 terraform.tfstate라는 파일이 생기는데 여기서 적용된 인프라의 버전을 관리하고 있으므로 이 파일도 보관하고 있어야 인프라를 변경했을 때 문제없이 배포할 수 있다.

여기서 설명한 전체 코드는 GitHub 저장소에 올려져 있다.

2016/09/23 03:38 2016/09/23 03:38

Apex - AWS Lambda 관리도구 #2

이 글은 Apex - AWS Lambda 관리도구 #1에서 이어진 글이다.


Lambda 함수의 배포와 실행

기능은 없지만, 설정이 완료되었다. 사용하려면 먼저 Lambda에 배포해야 한다.

$ apex deploy
  • creating function         env= function=hello
  • created alias current     env= function=hello version=1
  • function created          env= function=hello name=apex-example_hello version=1

apex deploy를 실행하면 프로젝트에 설정된 함수가 모두 배포한다. 특정 함수만 배포하고 싶다면 apex deploy hello처럼 이름을 지정하거나 apex deploy he*처럼 와일드카드를 쓸 수도 있다. 위 로그를 보면 apex-example_hello라는 이름으로 함수가 배포되었고 첫 배포이므로 버전이 1인 것을 볼 수 있다.

AWS의 Lambda에서 함수가 생성된 화면

AWS Lambda에 접속하면 함수가 만들어진 것을 볼 수 있다. AWS 웹 콘솔에서도 테스트해볼 수 있지만 apex를 이용해 보자.

$ apex invoke hello
{"hello":"world"}

apex invoke 함수명을 실행하면 바로 Lambda 함수를 테스트해 볼 수 있다. 이는 apex가 실제로 Lambda에서 함수를 실행하고 그 결과를 받아서 출력해 준 것이다. 당연히 인터넷이 연결되어 있어야 하고 속도에 따라서 호출 결과가 늦게 올 수도 있다. 처음 Lambda를 사용해 볼 때 개발이 어려워서 로컬에서 Lambda 환경과 유사하게 실행해 볼 방법을 많이 찾아봤었는데 Apex는 Lambda 환경을 에뮬레이팅하는 대신 Lambda 환경을 직접 이용한다. 그래서 인터넷이 필요한 단점은 있지만, 실제 Lambda 환경에서 직접 해볼 수 있다는 장점이 있고 명령어로 간단히 해볼 수 있으므로 별로 불편하지도 않다.

hello함수는 안 그렇지만 Lambda 함수에 입력을 전달해야 하는 때도 있다. 이런 경우 테스트를 하려면 터미널 기능을 그대로 이용하면 된다.

$ echo -n '{ "value": "Tobi the ferret" }' | apex invoke hello

$ apex invoke hello < event.json

위와 같이 하면 파이프로 전달한 JSON이나 파일의 내용이 함수의 입력으로 전달된다.

이제 index.js를 약간 수정해 보자.

// functions/hello/index.js
console.log('starting function')
exports.handle = function(e, ctx, cb) {
  console.log('processing event: %j', e)
  cb(null, e); // 수정된 부분
}

Lambda 함수에 전달된 입력은 첫 번째 인자인 e로 전달되는데 이 값을 그대로 반환하도록 수정했다. 함수를 수정했으니 다시 배포를 해야 한다.

$ apex deploy hello
  • config unchanged          env= function=hello
  • updating function         env= function=hello
  • updated alias current     env= function=hello version=2
  • function updated          env= function=hello name=apex-example_hello version=2

새로 배포가 되고 버전이 2로 올라갔다. 이제 입력값을 주어 다시 실행해 보면 변경된 것을 확인할 수 있다.

$ echo -n '{ "value": "Tobi the ferret" }' | apex invoke hello
{"value":"Tobi the ferret"}


Lamda 함수의 로그와 매트릭

index.js에서 console.log로 로그를 출력했는데 Lambda에서 이 로그 결과는 Cloudwatch에 남게 된다. 실제 Lambda 서비스에서 로그를 확인하는 건 좀 귀찮은 일인데 apex가 이 부분까지 지원하고 있다.

$ apex logs hello
/aws/lambda/apex-example_hello 2016-09-20T17:53:21.287Z undefined starting function
/aws/lambda/apex-example_hello START RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c Version: 2
/aws/lambda/apex-example_hello 2016-09-20T17:53:21.299Z 1e82d1fb-7f5b-11e6-9c79-5592aa65509c  processing event: {"value":"Tobi the ferret"}
/aws/lambda/apex-example_hello END RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c
/aws/lambda/apex-example_hello REPORT RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c Duration: 10.93 ms  Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 14 MB

앞에 시간과 함수명이 나와서 보기 어렵지만 끝부분을 보면 console.log로 출력된 결과를 볼 수 있다. 이 로그를 통해서 메모리 사용량과 실행시간도 알 수 있다.

$ apex logs hello -s 1h
/aws/lambda/apex-example_hello 2016-09-20T17:45:15.424Z undefined starting function
/aws/lambda/apex-example_hello START RequestId: fce399dd-7f59-11e6-af77-8300015b5dd0 Version: 1
/aws/lambda/apex-example_hello 2016-09-20T17:45:15.439Z fce399dd-7f59-11e6-af77-8300015b5dd0  processing event: {}
/aws/lambda/apex-example_hello END RequestId: fce399dd-7f59-11e6-af77-8300015b5dd0
/aws/lambda/apex-example_hello REPORT RequestId: fce399dd-7f59-11e6-af77-8300015b5dd0 Duration: 14.89 ms  Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 14 MB
/aws/lambda/apex-example_hello 2016-09-20T17:53:21.287Z undefined starting function
/aws/lambda/apex-example_hello START RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c Version: 2
/aws/lambda/apex-example_hello 2016-09-20T17:53:21.299Z 1e82d1fb-7f5b-11e6-9c79-5592aa65509c  processing event: {"value":"Tobi the ferret"}
/aws/lambda/apex-example_hello END RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c
/aws/lambda/apex-example_hello REPORT RequestId: 1e82d1fb-7f5b-11e6-9c79-5592aa65509c Duration: 10.93 ms  Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 14 MB

-s 1h와 같이 시간을 지정하면 지정된 시간 동안의 로그를 모두 볼 수 있고 -f옵션으로 로그를 추적해서 볼 수도 있다.

$ apex metrics hello

  hello
    total cost: $0.00
    invocations: 2 ($0.00)
    duration: 25ms ($0.00)
    throttles: 0
    errors: 0
    memory: 128

함수에 대한 매트릭도 바로 확인할 수 있다. 예제로 앞에서 2번 실행했으므로 2번 실행되었다고 나오는 걸 볼 수 있다.

Lambda 함수의 롤백과 제거

Lambda에는 버전 관리 기능이 없지만, apex가 배포되는 함수의 버전을 관리해 주므로 잘못되면 롤백을 할 수 있다.

$ apex rollback hello
  • rolling back              env= function=hello
  • rollback to version: 1    env= function=hello
  • function rolled back      current version=1 env= function=hello

$ apex invoke hello
{"hello":"world"}

apex rollback 함수명으로 버전이 다시 1로 돌아간 것을 볼 수 있고 실행결과도 예전으로 돌아왔다. 특정 버전으로 롤백하고 싶다면 apex rollback hello 1처럼 버전을 지정하면 된다.

$ apex delete hello
Are you sure? (yes/no) yes
  • deleting                  env= function=hello
  • function deleted          env= function=hello

함수가 필요 없어지면 apex delete 함수명으로 함수를 제거할 수 있다.

$ apex list

  hello (not deployed)
    runtime: nodejs4.3
    memory: 128mb
    timeout: 5s
    role: arn:aws:iam::410655858509:role/apex-example_lambda_function
    handler: index.handle

apex list로 프로젝트에서 관리하는 함수의 목록을 확인할 수 있다.


funcion.json

앞에서 project.json 파일로 프로젝트의 전역설정에 대해 설명을 했는데 함수별로 추가설정을 할 수 있다.

├── functions
│   └── hello
│       ├── funcion.json
│       └── index.js
└── project.json

위처럼 함수의 폴더 안에 funcion.json을 만들면 이 파일의 설정을 함수에 적용하고 설정 안 된 부분은 project.json의 설정을 사용한다. 이 파일에서 사용할 수 있는 설정은 다음과 같다.

  • description: 프로젝트에 대한 설명이다.(문자열)
  • runtime: Lambda의 런타임으로 다음 값을 사용할 수 있다.(문자열)

    • java: Java 8
    • python: Python 2.7
    • nodejs: Node.js 0.10
    • nodejs4.3: Node.js 4.3
    • golang: any version, Lambda에서는 원래 지원하지 않지만, Apex에서 지원한다.
  • handler: 이벤트 핸들러의 이름으로 다음이 기본값이다.

    • nodejs: index.handle (index.js파일에서 export로 내보낸 함수)
    • python: handle
    • java: lambda.Main::handler
  • memory: Lambda의 할당 메모리(정수, 메가바이트 단위)
  • timeout: Lambda의 함수 실행 만료시간(정수, 초 단위)
  • environment: Lambda 함수에 적용할 환경 변수이다.(객체)
  • retainedVersions: 롤백 등에 사용하기 위해 Lambda에서 유지할 함수의 버전 개수.
  • vpc: AWS의 VPC 설정(객체)
  • vpc.securityGroups: 시큐리티 그룹의 ID 목록(배열)
  • vpc.subnets: 서브넷 ID 목록(배열)

각 기능을 설명하느라 길어졌지만 실제로 약간 사용해보면 금세 익숙해질 정도로 간단하다. 써먹을 만한 함수를 작성한다면 고민할 요소가 좀 더 있는데 이 부분은 조만간 별도의 글로 올릴 예정이다.

2016/09/21 03:34 2016/09/21 03:34