SAM Initialization

這邊使用 sam init 來初始化專案。

  1$ sam init
  2
  3You can preselect a particular runtime or package type when using the `sam init` experience.
  4Call `sam init --help` to learn more.
  5
  6Which template source would you like to use?
  7	1 - AWS Quick Start Templates
  8	2 - Custom Template Location
  9Choice: 1
 10
 11Choose an AWS Quick Start application template
 12	1 - Hello World Example
 13	2 - Data processing
 14	3 - Hello World Example with Powertools for AWS Lambda
 15	4 - Multi-step workflow
 16	5 - Scheduled task
 17	6 - Standalone function
 18	7 - Serverless API
 19	8 - Infrastructure event management
 20	9 - Lambda Response Streaming
 21	10 - Serverless Connector Hello World Example
 22	11 - Multi-step workflow with Connectors
 23	12 - GraphQLApi Hello World Example
 24	13 - Full Stack
 25	14 - Lambda EFS example
 26	15 - Hello World Example With Powertools for AWS Lambda
 27	16 - DynamoDB Example
 28	17 - Machine Learning
 29Template: 1
 30
 31# 目前官方預設最常用的語言開發事 Python ,所以要選擇 N 以後,才可以選其他語言
 32Use the most popular runtime and package type? (Python and zip) [y/N]: N
 33
 34Which runtime would you like to use?
 35	1 - aot.dotnet7 (provided.al2)
 36	2 - dotnet8
 37	3 - dotnet6
 38	4 - go1.x
 39	5 - go (provided.al2)
 40	6 - go (provided.al2023)
 41	7 - graalvm.java11 (provided.al2)
 42	8 - graalvm.java17 (provided.al2)
 43	9 - java21
 44	10 - java17
 45	11 - java11
 46	12 - java8.al2
 47	13 - nodejs20.x
 48	14 - nodejs18.x
 49	15 - nodejs16.x
 50	16 - python3.9
 51	17 - python3.8
 52	18 - python3.12
 53	19 - python3.11
 54	20 - python3.10
 55	21 - ruby3.2
 56	22 - rust (provided.al2)
 57	23 - rust (provided.al2023)
 58Runtime: 13
 59
 60What package type would you like to use?
 61	1 - Zip
 62	2 - Image
 63Package type: 1
 64
 65Based on your selections, the only dependency manager available is npm.
 66We will proceed copying the template using npm.
 67
 68Select your starter template
 69	1 - Hello World Example
 70	2 - Hello World Example TypeScript
 71Template: 1
 72
 73Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: y
 74X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details
 75
 76Would you like to enable monitoring using CloudWatch Application Insights?
 77For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N
 78
 79Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: y
 80Structured Logging in JSON format might incur an additional cost. View https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-pricing for more details
 81
 82Project name [sam-app]:
 83
 84    -----------------------
 85    Generating application:
 86    -----------------------
 87    Name: sam-app
 88    Runtime: nodejs20.x
 89    Architectures: x86_64
 90    Dependency Manager: npm
 91    Application Template: hello-world
 92    Output Directory: .
 93    Configuration file: sam-app/samconfig.toml
 94
 95    Next steps can be found in the README file at sam-app/README.md
 96
 97
 98Commands you can use next
 99=========================
100[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
101[*] Validate SAM template: cd sam-app && sam validate
102[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch

檔案結構

  • event.json: 用來測試 Labmda 的
  • app.mjs: Lambda Function 原始碼
  • package.json: NPM 用來管理 Package 的檔案
  • test-handler: Lambda Unit Test
  • samconfig.toml: SAM CLI 的設定檔案
  • template.ymal: Infrastructure as code 架構的定義檔案
 1.
 2├── README.md
 3├── __init__.py
 4├── events
 5│   └── event.json
 6├── hello_world
 7│   ├── __init__.py
 8│   ├── app.py
 9│   └── requirements.txt
10├── samconfig.toml
11├── template.yaml
12└── tests
13    ├── __init__.py
14    ├── integration
15    │   ├── __init__.py
16    │   └── test_api_gateway.py
17    ├── requirements.txt
18    └── unit
19        ├── __init__.py
20        └── test_handler.py

Template YAML

  • AWSTemplateFormatVersion: AWS CloudFormation 的 Version
  • Transform: 告訴 CloudFormation 這是 SAM 的格式 YAML
  • Global: 這邊是針對某些服務資源,共同設定,像 Function 的 Tracing: Active 就是對全部的 Lambda 開啟 X-Ray
  • Reousrce: 這邊就是建立 AWS 上的資源, SAM 跟 CloudFormation 的定義有差別,下面會附上簡易差別圖,詳細資訊可參考官網
    • Type 是 Function 就是我們實際的 Lambda Function
      • CodeUri: 是 resource code 存放位置的路徑
      • Handler: 這邊是 filename.functionName 的格式
 1AWSTemplateFormatVersion: '2010-09-09'
 2Transform: AWS::Serverless-2016-10-31
 3Description: >
 4  sam-app
 5  Sample SAM Template for sam-app  
 6
 7Globals:
 8  Function:
 9    Timeout: 3
10    MemorySize: 128
11    Tracing: Active
12    LoggingConfig:
13      LogFormat: JSON
14  Api:
15    TracingEnabled: true
16Resources:
17  HelloWorldFunction:
18    Type: AWS::Serverless::Function 
19    Properties:
20      CodeUri: hello_world/
21      Handler: app.lambda_handler
22      Runtime: python3.9
23      Architectures:
24      - x86_64
25      Events:
26        HelloWorld:
27          Type: Api
28          Properties:
29            Path: /hello
30            Method: get
31
32Outputs:
33  HelloWorldApi:
34    Description: API Gateway endpoint URL for Prod stage for Hello World function
35    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
36  HelloWorldFunction:
37    Description: Hello World Lambda Function ARN
38    Value: !GetAtt HelloWorldFunction.Arn
39  HelloWorldFunctionIamRole:
40    Description: Implicit IAM Role created for Hello World function
41    Value: !GetAtt HelloWorldFunctionRole.Arn

CloudFormation vs SAM Resource

cloudformation_vs_sam

驗證 Template

AWS Sam 提供了 sam validate 去驗證 template 是否有問題

1$ sam validate 
2
3/Users/allen/sam-app/template.yaml is a valid SAM Template

如果我故意在 template 裡面寫沒有存在的 Type,會出現以下錯誤

1$ sam validate 
2
3E0001 Error transforming template: Resource with id [HelloWorldFunction] is invalid. Event with id [HelloWorld] is invalid. Resource dict has missing or invalid value for key Type. Event Type is: Api1.
4/Users/allen/sam-app/template.yaml:1:1
5
6Error: Linting failed. At least one linting rule was matched to the provided template.

Lambda Function

 1export const lambdaHandler = async (event, context) => {
 2    const response = {
 3      statusCode: 200,
 4      body: JSON.stringify({
 5        message: 'hello world',
 6      })
 7    };
 8
 9    return response;
10  };

Build Package

這邊使用 sam build 來建立 package

 1$ sam build
 2
 3Starting Build use cache
 4Manifest file is changed (new hash: c0e83ff3ce1bd02a0c2a7c02974c24ec) or dependency folder (.aws-sam/deps/1d492548-0d35-49f3-af42-0252668aa785) is missing for (HelloWorldFunction), downloading
 5dependencies and copying/building source
 6Building codeuri: /Users/allen/sam-app/hello-world runtime: nodejs20.x metadata: {} architecture: x86_64 functions: HelloWorldFunction
 7 Running NodejsNpmBuilder:NpmPack
 8 Running NodejsNpmBuilder:CopyNpmrcAndLockfile
 9 Running NodejsNpmBuilder:CopySource
10 Running NodejsNpmBuilder:NpmInstall
11 Running NodejsNpmBuilder:CleanUp
12 Running NodejsNpmBuilder:CopyDependencies
13 Running NodejsNpmBuilder:CleanUpNpmrc
14 Running NodejsNpmBuilder:LockfileCleanUp
15 Running NodejsNpmBuilder:LockfileCleanUp
16
17Build Succeeded
18
19Built Artifacts  : .aws-sam/build
20Built Template   : .aws-sam/build/template.yaml
21
22Commands you can use next
23=========================
24[*] Validate SAM template: sam validate
25[*] Invoke Function: sam local invoke
26[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
27[*] Deploy: sam deploy --guided

接著會在 local 產生 .aws-sam/build 資料夾。 在資料夾中,可以看到 node_modules 的資料,我們定義在 Package.json 的 modules 都會下載到這

  1$ tree .aws-sam/build
  2
  3.aws-sam/build
  4├── HelloWorldFunction
  5│   ├── app.mjs
  6│   ├── node_modules
  7│   │   ├── asynckit
  8│   │   │   ├── LICENSE
  9│   │   │   ├── README.md
 10│   │   │   ├── bench.js
 11│   │   │   ├── index.js
 12│   │   │   ├── lib
 13│   │   │   │   ├── abort.js
 14│   │   │   │   ├── async.js
 15│   │   │   │   ├── defer.js
 16│   │   │   │   ├── iterate.js
 17│   │   │   │   ├── readable_asynckit.js
 18│   │   │   │   ├── readable_parallel.js
 19│   │   │   │   ├── readable_serial.js
 20│   │   │   │   ├── readable_serial_ordered.js
 21│   │   │   │   ├── state.js
 22│   │   │   │   ├── streamify.js
 23│   │   │   │   └── terminator.js
 24│   │   │   ├── package.json
 25│   │   │   ├── parallel.js
 26│   │   │   ├── serial.js
 27│   │   │   ├── serialOrdered.js
 28│   │   │   └── stream.js
 29│   │   ├── axios
 30│   │   │   ├── CHANGELOG.md
 31│   │   │   ├── LICENSE
 32│   │   │   ├── MIGRATION_GUIDE.md
 33│   │   │   ├── README.md
 34│   │   │   ├── SECURITY.md
 35│   │   │   ├── dist
 36│   │   │   │   ├── axios.js
 37│   │   │   │   ├── axios.js.map
 38│   │   │   │   ├── axios.min.js
 39│   │   │   │   ├── axios.min.js.map
 40│   │   │   │   ├── browser
 41│   │   │   │   │   ├── axios.cjs
 42│   │   │   │   │   └── axios.cjs.map
 43│   │   │   │   ├── esm
 44│   │   │   │   │   ├── axios.js
 45│   │   │   │   │   ├── axios.js.map
 46│   │   │   │   │   ├── axios.min.js
 47│   │   │   │   │   └── axios.min.js.map
 48│   │   │   │   └── node
 49│   │   │   │       ├── axios.cjs
 50│   │   │   │       └── axios.cjs.map
 51│   │   │   ├── index.d.cts
 52│   │   │   ├── index.d.ts
 53│   │   │   ├── index.js
 54│   │   │   ├── lib
 55│   │   │   │   ├── adapters
 56│   │   │   │   │   ├── README.md
 57│   │   │   │   │   ├── adapters.js
 58│   │   │   │   │   ├── http.js
 59│   │   │   │   │   └── xhr.js
 60│   │   │   │   ├── axios.js
 61│   │   │   │   ├── cancel
 62│   │   │   │   │   ├── CancelToken.js
 63│   │   │   │   │   ├── CanceledError.js
 64│   │   │   │   │   └── isCancel.js
 65│   │   │   │   ├── core
 66│   │   │   │   │   ├── Axios.js
 67│   │   │   │   │   ├── AxiosError.js
 68│   │   │   │   │   ├── AxiosHeaders.js
 69│   │   │   │   │   ├── InterceptorManager.js
 70│   │   │   │   │   ├── README.md
 71│   │   │   │   │   ├── buildFullPath.js
 72│   │   │   │   │   ├── dispatchRequest.js
 73│   │   │   │   │   ├── mergeConfig.js
 74│   │   │   │   │   ├── settle.js
 75│   │   │   │   │   └── transformData.js
 76│   │   │   │   ├── defaults
 77│   │   │   │   │   ├── index.js
 78│   │   │   │   │   └── transitional.js
 79│   │   │   │   ├── env
 80│   │   │   │   │   ├── README.md
 81│   │   │   │   │   ├── classes
 82│   │   │   │   │   │   └── FormData.js
 83│   │   │   │   │   └── data.js
 84│   │   │   │   ├── helpers
 85│   │   │   │   │   ├── AxiosTransformStream.js
 86│   │   │   │   │   ├── AxiosURLSearchParams.js
 87│   │   │   │   │   ├── HttpStatusCode.js
 88│   │   │   │   │   ├── README.md
 89│   │   │   │   │   ├── ZlibHeaderTransformStream.js
 90│   │   │   │   │   ├── bind.js
 91│   │   │   │   │   ├── buildURL.js
 92│   │   │   │   │   ├── callbackify.js
 93│   │   │   │   │   ├── combineURLs.js
 94│   │   │   │   │   ├── cookies.js
 95│   │   │   │   │   ├── deprecatedMethod.js
 96│   │   │   │   │   ├── formDataToJSON.js
 97│   │   │   │   │   ├── formDataToStream.js
 98│   │   │   │   │   ├── fromDataURI.js
 99│   │   │   │   │   ├── isAbsoluteURL.js
100│   │   │   │   │   ├── isAxiosError.js
101│   │   │   │   │   ├── isURLSameOrigin.js
102│   │   │   │   │   ├── null.js
103│   │   │   │   │   ├── parseHeaders.js
104│   │   │   │   │   ├── parseProtocol.js
105│   │   │   │   │   ├── readBlob.js
106│   │   │   │   │   ├── speedometer.js
107│   │   │   │   │   ├── spread.js
108│   │   │   │   │   ├── throttle.js
109│   │   │   │   │   ├── toFormData.js
110│   │   │   │   │   ├── toURLEncodedForm.js
111│   │   │   │   │   └── validator.js
112│   │   │   │   ├── platform
113│   │   │   │   │   ├── browser
114│   │   │   │   │   │   ├── classes
115│   │   │   │   │   │   │   ├── Blob.js
116│   │   │   │   │   │   │   ├── FormData.js
117│   │   │   │   │   │   │   └── URLSearchParams.js
118│   │   │   │   │   │   └── index.js
119│   │   │   │   │   ├── common
120│   │   │   │   │   │   └── utils.js
121│   │   │   │   │   ├── index.js
122│   │   │   │   │   └── node
123│   │   │   │   │       ├── classes
124│   │   │   │   │       │   ├── FormData.js
125│   │   │   │   │       │   └── URLSearchParams.js
126│   │   │   │   │       └── index.js
127│   │   │   │   └── utils.js
128│   │   │   └── package.json
129│   │   ├── combined-stream
130│   │   │   ├── License
131│   │   │   ├── Readme.md
132│   │   │   ├── lib
133│   │   │   │   └── combined_stream.js
134│   │   │   ├── package.json
135│   │   │   └── yarn.lock
136│   │   ├── delayed-stream
137│   │   │   ├── License
138│   │   │   ├── Makefile
139│   │   │   ├── Readme.md
140│   │   │   ├── lib
141│   │   │   │   └── delayed_stream.js
142│   │   │   └── package.json
143│   │   ├── follow-redirects
144│   │   │   ├── LICENSE
145│   │   │   ├── README.md
146│   │   │   ├── debug.js
147│   │   │   ├── http.js
148│   │   │   ├── https.js
149│   │   │   ├── index.js
150│   │   │   └── package.json
151│   │   ├── form-data
152│   │   │   ├── License
153│   │   │   ├── README.md.bak
154│   │   │   ├── Readme.md
155│   │   │   ├── index.d.ts
156│   │   │   ├── lib
157│   │   │   │   ├── browser.js
158│   │   │   │   ├── form_data.js
159│   │   │   │   └── populate.js
160│   │   │   └── package.json
161│   │   ├── mime-db
162│   │   │   ├── HISTORY.md
163│   │   │   ├── LICENSE
164│   │   │   ├── README.md
165│   │   │   ├── db.json
166│   │   │   ├── index.js
167│   │   │   └── package.json
168│   │   ├── mime-types
169│   │   │   ├── HISTORY.md
170│   │   │   ├── LICENSE
171│   │   │   ├── README.md
172│   │   │   ├── index.js
173│   │   │   └── package.json
174│   │   └── proxy-from-env
175│   │       ├── LICENSE
176│   │       ├── README.md
177│   │       ├── index.js
178│   │       ├── package.json
179│   │       └── test.js
180│   └── package.json
181└── template.yaml