Serverless 프레임워크 빠르게 배우기 (2)

Serverless 프레임워크 빠르게 배우기 (2)

지난 포스트에서 serverless의 기본적인 핵심 개념들과 그 중 Services까지 정리를 했다. 이번에는 Functions에 대해서 정리해보자. (Events까지 보려고 했는데 생각보다 함수파트 내용이 복잡하고 많으니까 천천히 다시 볼 필요가 있는 것 같음)

Functions

이 글에서는 Provider가 AWS이므로 Functions는 Lambda를 뜻한다.

설정

모든 함수들은 serverless.ymlfunctions 속성 아래서 발견할 수 있다. 아래 예시를 확인해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# serverless.yml
service: myService

# ...

functions:
hello:
handler: handler.hello # required, handler set in AWS Lambda
name: ${self:provider.stage}-lambdaName # 배포될 람다 이름 (옵션)
description: 함수가 무슨 일을 하는지에 대해서.
runtime: python2.7 # 기본적으로는 provider에서 정의한 runtime
memorySize: 512 # 디폴트는 1024 MB
timeout: 10 # 타임 아웃 디폴트는 6초
reservedConcurrency: 5 # optional, reserved concurrency limit for this function. By default, AWS uses account concurrency limit
tracing: PassThrough # Active or PassThrough가 가능함

handler라는 속성은 실행하려고 하는 함수를 담고 있는 모듈을 가리키고 있다. functions라는 속성에 여러 함수들을 담을 수 있다. 여러 함수들을 작성한 경우 함수들은 그 세팅을 provider 속성에서 많이 상속 받아 온다.

예를 들어서 아래의 경우, 모든 함수들의 memorySize는 512가 된다. 그리고 함수 단위에서 같은 이름으로 새로 정의할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
service: myService

provider:
name: aws
runtime: nodejs12.x
memorySize: 512 # 아래 함수들에게 기본으로 적용됨

functions:
functionOne:
handler: handler.functionOne
functionTwo:
handler: handler.functionTwo
memorySize: 1024 # provider에서 받은 속성을 덮어 씀

함수들을 다른 파일들에 분리할 때는, 함수들을 배열의 형태로 정의하는 것이 유용하다.

1
2
3
functions:
- $(file(../foo-functions.yml))
...
1
2
3
4
5
# foo-functions.yml
getFoo:
handler: handler.foo
deleteFoo:
handler: handler.foo

이제 구체적인 설정들에 대해서 하나씩 살펴볼 것이다.

권한 (Permissions)

모든 AWS 람다 함수는 다른 AWS 인프라 리소스들과 상호작용 하기 위해서 권한이 필요하다. 이 권한들은 IAM Role을 통해서 설정하는 것인데, 이런 권한 정책을 provider.iamRoleStatements 속성을 통해서도 설정할 수 있다. 아래 몇 가지 예시를 확인해보자, 첫 번째는 serverless.yml에 정의되는 모든 함수들이 DynamoDB에 대한 권한을 갖게 되는 예시이고, 두 번째는 S3 버킷에 오브젝트를 놓는 것을 허용하는 권한이다.

첫 번째 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# serverless.yml
service: myService

provider:
name: aws
runtime: nodejs12.x
iamRoleStatements: # 모든 람다 함수의 권한
- Effect: Allow
Action: # 특정 리전에 DynamoDB 테이블 권한을 줌
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:us-east-1:*:*"

functions:
functionOne:
handler: handler.functionOne
memorySize: 512

두 번째 예시

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
# serverless.yml
service: myService
provider:
name: aws
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:ListBucket"
# 여기에 CloudFormation 문법을 적어 둘 수 있다.
# 여기에 모든 내용들이 CloudFormation으로 전환되기 때문에.
Resource:
{
"Fn::Join":
["", ["arn:aws:s3:::", { "Ref": "ServerlessDeploymentBucket" }]],
}
- Effect: "Allow"
Action:
- "s3:PutObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- "Ref": "ServerlessDeploymentBucket"
- "/*"

functions:
functionOne:
handler: handler.functionOne
memorySize: 512

serverless.yml에 정의하지 않고 ARN을 사용해 원래 있던 IAM Role을 사용할 수 있다.

1
2
3
4
5
# serverless.yml
service: new-service
provider:
name: aws
role: arn:aws:iam::YourAccountNumber:role/YourIamRole

VPC 설정

serverless.ymlvpc 객체 속성을 함수 설정 부분에 추가함으로써, 구체적인 함수에 적용되는 VPC 설정을 추가할 수 있다. 이 객체는 VPC가 구성되기 위해 필요한 securityGroupIdssubnetIds 배열 속성들을 포함해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
service: service-name
provider: aws

functions:
hello:
handler: handler.hello
vpc:
securityGroupIds:
- securityGroupId1
- securityGroupId2
subnetIds:
- subnetId1
- subnetId2

구체적으로 말고 해당 서비스 안에 사용되는 모든 함수에 적용하고 싶다면 항상 그랬듯, provider 부분에 설정을 해줘도 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
service: service-name
provider:
name: aws
vpc:
securityGroupIds:
- securityGroupId1
- securityGroupId2
subnetIds:
- subnetId1
- subnetId2

functions:
hello: # 이 함수는 상위 VPC 설정을 덮어 쓸 것임.
handler: handler.hello
vpc:
securityGroupIds:
- securityGroupId1
- securityGroupId2
subnetIds:
- subnetId1
- subnetId2
users: # 이 함수는 그냥 위의 VPC 설정을 그대로 사용할 것임
handler: handler.users

위 설정에 따라서, 배포하면 람다 함수와 함께 VPC 설정이 배포될 것이다.

VPC IAM Permissions

(이 부분은 사실 배경 지식 부족으로 매끄럽게 읽히지가 않았다. 이후 공부 해보면서 알게 되면 보충해보도록 하자. 아마 RDS 연결하면서 VPC 설정은 더 자세하게 공부해야 할 것 같다.)

람다 함수의 실행 역할은 반드시 Elastic Network Interface(ENI)를 만들고, 삭제하는 권한이 있어야 한다. VPC 설정이 구성될 때, 기본 AWS AWSLambdaVPCAccessExecutionRole이 람다 실행 역할과 연관지어진다. 커스텀 역할이 제공 되는 경우엔, 적절한 ManagedPolicyArns가 포함되어 있어야 한다. 자세한 정보는 여기 링크에서 확인해보자.

VPC Lambda Internet Access

기본적으로, 람다 함수가 VPC 내부에서 실행될 때, 함수는 인터넷 접근을 잃고 몇 AWS 내부의 리소스들을 사용할 수 없게 된다. S3 리소스와 DynamoDB 리소스가 VPC 내부의 람다에서 동작하게 하기 위해서는 하나의 VPC 엔드 포인트가 만들어져야 한다. 더 자세한 정보는 여기 링크에서 확인해보자. 다른 Kinesis streams 같은 서비스들을 사용할 수 있게 하려면, 하나의 NAT 게이트웨이가 람다를 돌릴 때 사용되는 서브넷 안에서 설정 되어 있어야 한다. 더 자세한 정보는 여기 링크에서 확인해보자.

환경 변수

환경 변수도 마찬가지로 전역적으로 provider에 설정해주거나 함수 단위로 설정해줄 수 있다. environment 속성에 담아주면 된다. 기본적으로 provider와 함수 쪽에 설정된 환경 변수는 merge되지만, 같은 key값을 가진 환경 변수는 함수 쪽에 설정된 값으로 덮어 씌워진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# serverless.yml
service: service-name
provider:
name: aws
environment:
SYSTEM_NAME: mySystem
TABLE_NAME: tableName1

functions:
hello:
# 이 함수는 SYSTEM_NAME, TABLE_NAME 환경 변수 사용 가능함
handler: handler.hello
users:
# 이 함수도 둘 다 사용 가능하지만, TABLE_NAME은 함수 부분에서 정의된 변수를 사용함
handler: handler.users
environment:
TABLE_NAME: tableName2

만약 함수의 환경변수가 machine(개발 하고 있는 호스트를 말하는 것 같음)의 환경 변수들과 일치하기를 바란다면, 여기 문서를 확인해 보자

Tags

키/값 태그를 함수에 붙이는 설정값이다. 이렇게 해서 붙여진 태그는 AWS 콘솔에 나타나고, 함수들을 태그로 찾거나 그룹 짓기 쉽다. 이 값도 위와 마찬가지로 functions 레벨에서 정의할 수도 있고, provider 레벨에서 정의할 수도 있지만, 환경 변수 처럼 같은 키 값을 가진 태그는 구체적인 함수 레벨 것으로 덮어 씌워진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# serverless.yml
service: service-name
provider:
name: aws
tags:
foo: bar
baz: qux

functions:
hello:
# 이 함수는 foo, baz 태그가 적용 됨
handler: handler.hello
users:
# 이 함수도 foo, baz 태그가 적용 되는데, foo 값은 함수 레벨에서 정의된 값으로 사용된다.
handler: handler.users
tags:
foo: quux

태그를 사용하는 좋은 예는 아래와 같다.

  • 비용 측정용 (env: prod로 붙여두고 체크)
  • 레거시 코드 트랙킹 (runtime: node0.10 붙여두면 레거시 코드 찾기 쉬움)

Layers

람다 Layers를 사용하기 위한 설정 값도 정의할 수 있다. 람다 Layer는 2018년 말에 나온 것 같은데, serverless.yml에서 아래와 같이 설정해주면 사용할 수 있다.

1
2
3
4
5
functions:
hello:
handler: handler.hello
layers:
- arn:aws:lambda:region:XXXXXX:layer:LayerName:Y

Layers에 대한 설명이 따로 있어서 자세하게 보는 건 다음으로 미루자.

로그 그룹 리소스

기본적으로 serverless는 람다 함수들을 위한 로그 그룹을 만든다. 이렇게 함으로써 나중에 서비스를 삭제할 때 로그 그룹을 정리하기 쉽게 해주고, 람다 IAM 권한을 더 구체적이고 안전하게 만들어준다.

Versioning Deployed Functions

마찬가지로 기본적으로 serverless는 배포시마다 함수의 버전을 만든다. 이건 선택적인데, provider 레벨에서 versionFunctions 속성을 true, false로 두는 것으로 켜거나 끌 수 있다.

1
2
provider:
versionFunctions: false

DLQ (Dead Letter Queue)

DLQ는 람다 함수가 실행에 실패하면 해당 정보를 SNS topic이나 SQS queue를 통해 전달해주는 것을 말한다. 이 정보로 실패한 람다에 대한 진단을 내리고 반응할 수 있다.

serverless 에서는 DLQ에 대한 설정을 SNS topic과 onError 파라메타를 통해서 설정할 수 있다. 이 설정은 함수 레벨에서 arn을 지정해주는 것으로 동작한다. (SQS는 문제가 있나봄)

1
2
3
4
5
6
7
8
9
10
11
service: service

provider:
name: aws
runtime: nodejs12.x

functions:
hello:
handler: handler.hello
onError: arn:aws:sns:us-east-1:XXXXXX:test
# Ref, Fn::GetAtt and Fn::ImportValue are supported as well

KMS Keys

람다는 시크릿 키를 위해서 KMS를 사용한다. serverless에서는 awsKmsKeyArn 속성 값으로 KMS를 지정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
service:
name: service-name
awsKmsKeyArn: arn:aws:kms:us-east-1:XXXXXX:key/some-hash

provider:
name: aws
environment:
TABLE_NAME: tableName1

functions:
hello: # 전역 설정된 KMS를 사용하지 않고 함수 레벨에서 정의된 KMS 사용
handler: handler.hello
awsKmsKeyArn: arn:aws:kms:us-east-1:XXXXXX:key/some-hash
environment:
TABLE_NAME: tableName2
goodbye:
handler: handler.goodbye

환경 변수에 시크릿키를 저장할 때 AWS는 민감한 정보를 암호화 할 것을 추천한다. 그래서 KMS를 사용하는 튜토리얼도 제공해주고 있다.

AWS X-Ray Tracing

serverless에서 tracing 속성 값을 적어주는 것으로, 람다 함수에 AWS X-Ray Tracing 서비스를 사용할 수 있다.

1
2
3
4
5
6
7
service: myService

provider:
name: aws
runtime: nodejs12.x
tracing:
lambda: true

그리고 또 이 변수를 함수 단위를 기본으로 설정할 수 있다. 위와 마찬가지로 provider 레벨에서 설정한 값을 덮어 쓴다.

1
2
3
4
5
6
7
functions:
hello:
handler: handler.hello
tracing: Active
goodbye:
handler: handler.goodbye
tracing: PassThrough

마치며

VPC와 다른 리소스를 함께 쓰는 것에 대해서 이론적으로 감은 온 것 같다. 구체적인 상황별 문서도 같이 붙여놔서 나중에 참고하기 좋을 것 같다.

Reference

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×