# 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 名稱 ``` ---