# Serverless Framework
###### tags: `AWS`,`Serverless`
---
## Serverless
Serverless 架構流行了一陣子了,以 function 為單位,讓開發者專注於程式開發,無需擔心維護 server 問題。這使許多雲端服務商推出 serverless 服務,如 AWS Lambda 及 Google Cloud Function。
## How to build serverless applications ?
有幾種部署方式:
* AWS console : 手動到 AWS console 設定,同環境需重複設定多次, 設定流程難以文件化。
* AWS CloudFormation : CloudFormation 可以把環境部署文件化,但 Lambda Function code 必須自行另外打包上傳到 s3,就 Lambda 部署而言,設定相較於 JavaScript library 複雜。
* JavaScript library : [Serverless Framework](https://serverless.com/framework/docs/) or [AWS Amplify](https://aws-amplify.github.io/docs/),提供簡單指令即可部署
---
## Serveless Framework
---
### Introduction
* Serverless Inc. released the Serverless Framework open source project in 2015.
* The easy and open way to build serverless applications.
* Support AWS Lambda, Google Cloud Functions, IBM Cloud, Azure & more.
---
### Example
---
##### Install Serverless Framework
```
yarn global add serverless
```
or
```
yarn add serverless
```
---
##### Create an index.js file
建立 Hello World 的 lambda function code:
```javascript=
module.exports.hanlder = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Hello World!',
})
}
callback(null, response)
}
```
---
##### Create a serverless.yml
設定 yml 檔,handler 指向 index.js, events 設定 http method
```yaml=
# serverless.yml
service: my-lambda
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
functions:
app:
handler: index.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
```
---
##### Deploy function
部署 lambda
```
sls deploy
```
Serverless Framework 會自動執行下列流程
```flow
st=>start: sls deploy
op=>operation: Packaging service
op2=>operation: Uploading CloudFormation template & lambda .zip file to S3
op3=>operation: Creating/Updating CloudFormation Stack
e=>end: Stack update finished
st->op->op2->op3->e
```
note:
Packaging service : 將 serverless.yml 轉換成 CloudFormation template (JSON), 並將 lambda 打包成 .zip 檔, 相關檔案將放在 .serverless 資料夾下
Uploading CloudFormation file & service .zip file to S3 : 將 CloudFormation template 跟 .zip 檔上傳到 S3, 所以 serverless 會自動建立專屬放 serverless 檔案的 S3
Creating/Updating CloudFormation Stack : 建立 CloudFormation stack, 並執行 CloudFormation template 設定的內容
---
### Serveless Framework deployment result
完成部署後會給 Lambda 的 end point,發 request 時會先到 API Gateway ,再去呼叫 Lambda Function
```flow
st=>start: xxxx.execute-api.us-east-1.amazonaws.com/dev
op=>operation: API Gateway
op2=>operation: Lambda Function
st->op->op2
```
---
## Serverless Framework YAML
serverless.yml 是 Serveless Framework 核心,裡頭會設定環境佈署方式。舉一些常見的用法及設定。
- Variables
- Environment
- Intrinsic Function
- Lambda Function
- DynamoDB
- S3 Bucket
- AppSync
---
### Variables
Variable sources
- Environment variables : ``` ${env:STAGE} ```
- CLI options : ${opt:stage}
```
sls deploy --stage dev
```
- External YAML/JSON files : ``` ${file(./config.dev.yml)} ```
- Referencing S3 Objects or CloudFormation Outputs
---
### Environment
Allow to pass static information into Lambda Function
```yaml=
# serverless.yml
provider:
environment:
STAGE: dev
USER_TABLE: UserList
```
```javascript=
//javascript
const TABLE_NAME = process.env.USER_TABLE
```
---
### Intrinsic Function
<br>
[AWS CloudFormation Intrinsic Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)
---
#### 串接數組
```yaml=
Fn::Join:
- '/'
-- 'table'
-- 'aaa'
```
```
Out: table/aaa
```
---
#### 取得 Resource attributeName
```yaml=
Fn::GetAtt:[MyS3Bucket, Arn]
```
```
Out: 回傳 logical ID 為 MyS3Bucket 的 Arn 屬性值
```
---
---
### Lambda Function
基本設置可以參考官網,以下記錄一些比較特別的設定。
---
#### Schedule
可以設定 schedule event,CloudWatch 會在設定的時間發送 event 給 Lambda Function。
---
#### Cold starts in AWS Lambda
- cold start 時間 : C# > JAVA >>> nodeJS > Python
- Lambda package size 不會影響 cold start 時間
- 整體而言有 60% lambda functions stay warm 介於 45~60 min 之間, 使用越多 memory 的 lambda function, 其 container 會被 AWS 較早關閉, 故 stay warm 時間會較短
- 設定 VPC 會增加 cold start 時間
note:
cold start : AWS 進行運行 lambda function 的 container 初始化過程 (container initialization) 稱為 cold start, 此 container 存在一段時間後才會被關閉, 這段期間若有調用 lambda function, 將在既有的 container 運行, 無需再 cold start, 若 container 已被關閉, 在必須再重新初始化
---
### DynamoDB
---
#### Basic Components
* Tables
* Items
* Attributes
note:
* Tables:
類似於 RDBMS 的 Table.
DynamoDB Table 是一個儲存集合單位。
相當於 MongoDB 的 Collection
* Items:
每個 Table 可以有多個 Items,相當於 RDBMS 的 Rows。
每個 Items 可包含多個 Attributes
相當於 MongoDB 的 Document
* Attributes:
每個 Items 由一個或多個 Attributes 組成
Attribute 的資料型態有 String, Number, Binary
---
#### serverless.yml dynamodb 基本的設定
設定權限
```yaml=
# serverless.yml
provider:
...
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:*Item"
- "dynamodb:Query"
- "dynamodb:Scan"
Resource:
- Fn::GetAtt: [MyTable, Arn]
...
...
```
設定 DB
```yaml=
...
resources:
Resources:
MyTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: N
- AttributeName: account
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
- AttributeName: account
KeyType: RANGE
TableName: 'MyTable'
...
```
---
#### Primary Key
Two different kinds of primary keys
- Partition key
-- Unique
-- Hash attribute
- Partition key and sort key
-- Composite key, partition key + sort key must be unique
-- Hash attribute and range attribute
note:
* Partition key(分區 key):
DynamoDB 利用這個值透過內部的 hash function,然後依據 hash 過的值,決定資料要放在哪個實體的儲存體 (Storage)。
基本上,不會有重複的 hash value,也就是不會有重複的 partition key。
* Partition key and sort key(分區 key 與排序 key):
使用兩個 attribute 的複合鍵 (composite key): partition key + sort key, 或者稱為 hash key + range key
sort key 又叫 range attribute
如果 sort key 存在,那麼 partition key 可以重複
hash key + range key 必須是唯一
最常用的例子就是 unique key + date range 這樣的組合。
---
#### Secondary Indexes
- More flexibility when querying data.
- Global secondary index & Local secondary index
- Define up to 5 global secondary indexes and 5 local secondary indexes per table.
note:
* Secondary Indexes 有自己的 key schema, GSI 有 自己的 partition key 及 sort key, 而 LSI 的 partition key 必須跟 Table 的 partition key 一致
* 若要對 Table partition key 之外的 attributes 作 query 或是 sort key 之外的 attributes 作排序, 需設定 Secondary Indexes
---
#### Throughput Capacity & Auto Scaling
- Read capacity unit : 4KB/s
- Write capacity unit : 1KB/s
- Auto Scaling : Manages throughput capacity for tables and global secondary indexes
note:
Read capacity unit : 每秒一次 or 兩次一致的 consistent read 最多4KB
Write capacity unit : 每秒最多1KB的項目的一次寫入
Auto Scaling : 管理 tables and global secondary indexes 讀寫容量, 可以為讀取和寫入容量單位定義範圍(上限和下限)。還可以在該範圍內定義目標利用率百分比
---
#### TimeToLiveSpecification
DynamoDB 可以設定 [TTL](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-timetolivespecification.html),時間到就會自動幫忙清除該筆資料。
---
#### serverless.yml dynamodb 進階的設定
```yaml=
...
resources:
Resources:
MyTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: N
- AttributeName: account
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
- AttributeName: account
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
TimeToLiveSpecification:
AttributeName: exp
Enabled: true
TableName:
Fn::Join:
- "-"
- - ${self:custom.MyTableName}
- ${self:custom.stage}
...
```
---
### S3 Bucket
- Serverless Framework Plugin : [serverless-finch](https://github.com/fernando-mc/serverless-finch)
```yaml=
custom:
client:
bucketName: MyBucketName
distributionFolder: web
plugins:
- serverless-finch
```
```
sls client deploy
```
---
### AppSync
- Serverless Framework Plugin : [serverless-appsync-plugin](https://github.com/sid88in/serverless-appsync-plugin)
```yaml=
name: AppSync name
authenticationType: 驗證方式, API Key, cognito... 等等
logConfig: AppSync log 設定
mappingTemplatesLocation: mapping template vtl 檔存放位置
mappingTemplates:
- dataSource: dataSource 名稱
type: Mutation or Query
field: field name
request: request vtl 檔名
response: response vtl 檔名
schema: schema.graphql 檔案位置
dataSources:
- type: AMAZON_DYNAMODB or 其他
name: dataSource 名稱
```
---