Open14

lambdaのローカル実行・デプロイについて

paciolipacioli

AWS SAM のインストール前に以下を揃えておく必要がある。

  • AWS アカウント
    • 今回は既存の自分のアカウントを利用する
  • AWS アカウントに対する IAM の許可設定 (管理者権限の付与)
    • 自分のアカウントがすでに管理者権限となっていたため設定は不要
  • AWS CLI に認証情報を設定する
  • Docker のインストール
    • Docker for Mac が入っていたのでOK
  • Homebrew のインストール
    • すでに入っているのでOK
  • AWS SAM CLI をインストール
paciolipacioli

これを実行と書いているけど、 tap ってなんやろ。

brew tap aws/tap

brew tapとは - Qiita

brew tapとは公式以外のリポジトリをフォーミュラとしてHomebrewに追加するもので、brewのもとでinstall,uninstall,updateなどが行えます。もちろん自分が公開しているものも簡単に追加できます。

そうなんや。

paciolipacioli

AWS SAM CLI のインストール

公式の通り以下のコマンドを実行。
いけたっぽい。

ステップ 5: AWS SAM CLI をインストールする

brew tap aws/tap
brew install aws-sam-cli
...
sam --version
# AM CLI, version 1.62.0

AWS SAM CLI のアップグレードとアンインストールの手順も紹介されてた。
実行はしてないけど載せとく。

アップグレード

brew upgrade aws-sam-cli

アンインストール

brew uninstall aws-sam-cli
paciolipacioli

チュートリアルに従い、 Hello World のサンプルサーバーレスアプリケーションを作成する。
公式チュートリアルでは runtime に python を指定しているが、 python 分からないので Node.js にする。

実行結果

sam init
# Which template source would you like to use?
# 	1 - AWS Quick Start Templates
# 	2 - Custom Template Location
# Choice: 1
# 
# Choose an AWS Quick Start application template
# 	1 - Hello World Example
# 	2 - Multi-step workflow
# 	3 - Serverless API
# 	4 - Scheduled task
# 	5 - Standalone function
# 	6 - Data processing
# 	7 - Infrastructure event management
# 	8 - Serverless Connector Hello World Example
# 	9 - Multi-step workflow with Connectors
# 	10 - Lambda EFS example
# 	11 - Machine Learning
# Template: 1
# 
# Use the most popular runtime and package type? (Python and zip) [y/N]: N
# 
# Which runtime would you like to use?
# 	1 - dotnet6
# 	2 - dotnet5.0
# 	3 - dotnetcore3.1
# 	4 - go1.x
# 	5 - graalvm.java11 (provided.al2)
# 	6 - graalvm.java17 (provided.al2)
# 	7 - java11
# 	8 - java8.al2
# 	9 - java8
# 	10 - nodejs16.x
# 	11 - nodejs14.x
# 	12 - nodejs12.x
# 	13 - python3.9
# 	14 - python3.8
# 	15 - python3.7
# 	16 - ruby2.7
# 	17 - rust (provided.al2)
# Runtime: 10
# 
# What package type would you like to use?
# 	1 - Zip
# 	2 - Image
# Package type: 1
# 
# Based on your selections, the only dependency manager available is npm.
# We will proceed copying the template using npm.
# 
# Select your starter template
# 	1 - Hello World Example
# 	2 - Hello World Example TypeScript
# 	3 - Hello World Example TypeScript w/ Lambda Powertools
# Template: 2
# 
# Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]:
# 
# Project name [sam-app]:
# 
# Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)
# 
#     -----------------------
#     Generating application:
#     -----------------------
#     Name: sam-app
#     Runtime: nodejs16.x
#     Architectures: x86_64
#     Dependency Manager: npm
#     Application Template: hello-world-typescript
#     Output Directory: .
# 
#     Next steps can be found in the README file at ./sam-app/README.md

ほんだら、カレントディレクトリに sam-app ディレクトリができた。

ls
# sam-app/

sam-app ディレクトリの中身はこう。

TypeScript のテンプレートあるのありがたい。

paciolipacioli

AWS SAM が生成してくれたテンプレートファイルの中で以下は特に重要らしい。

チュートリアル: Hello World アプリケーションのデプロイ - AWS Serverless Application Model

以下の 3 つのファイルは特に重要です。

  • AWS: アプリケーションの AWS SAM リソースを定義する template.yaml テンプレートが含まれます。
  • hello_world/app.py: 実際の Lambda ハンドラーロジックが含まれます。
  • hello_world/requirements.txt: アプリケーションが必要とするすべての Python 依存関係が含まれ、sam build に使用されます。

Node.js に置き換えるとこれらのファイルっぽい。

  • template.yaml
    • ちょっと中を覗いてみるとエントリーポイントとなるソースファイルの指定とか、ビルドする ECMAScript のバージョンの指定とか、タイムアウトの時間とか、そういうのが記載されている。
  • hello-world/app.ts
  • hello-world/package.json
paciolipacioli

続いて、 sam-app ディレクトリに移動して sam build を実行するみたいなので実行。
ほいだら、エラー出てきた。

sam build
# ...
# Running NodejsNpmEsbuildBuilder:CopySource
# Running NodejsNpmEsbuildBuilder:NpmInstall
# 
# Build Failed
# Error: NodejsNpmEsbuildBuilder:NpmInstall - NPM Failed: /private/var/folders/bm/dbnmjyzd185dnm1zp3z1m6_w0000gn/T/tmp6tx42w9a/node_modules/esbuild/install.js:153
#     } catch {
           ^
# 
# SyntaxError: Unexpected token {
#     at createScript (vm.js:80:10)

なんかよくわからないけど、 SyntaxError と出てるのでローカル実行環境の Node.js のバージョンが古いのがだめなのかな?と思って、ローカル実行環境の Node.js のバージョンを SAM で指定した Node.js のバージョンと同じバージョンにして再度実行したらいけた。 (案件の対応でかなり古い Node.js のバージョンを利用していた)

nodebrew use 16.7.0
# use v16.7.0

sam build
# ...
# Build Succeeded
# 
# Built Artifacts  : .aws-sam/build
# Built Template   : .aws-sam/build/template.yaml
# 
# Commands you can use next
# =========================
# [*] Validate SAM template: sam validate
# [*] Invoke Function: sam local invoke
# [*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
# [*] Deploy: sam deploy --guided

なんかローカル環境での実行とかテストの実行とかデプロイの実行とかできそうなコメントが出てきた。
ちなみに sam build では以下のようなことを実施しているらしい。

チュートリアル: Hello World アプリケーションのデプロイ - AWS Serverless Application Model

AWS SAM が実行する事柄:

AWS SAM CLI には、依存関係を構築するための多数の Lambda ランタイムの抽象化が含まれており、すべてのパッケージ化およびデプロイ準備が整うように、ソースコードをステージングフォルダにコピーします。> sam build コマンドは、アプリケーションが持つあらゆる依存関係を構築し、zip 形式で圧縮され、Lambda にアップロードされる .aws-sam/build 下のフォルダにアプリケーションソースコードをコピーします。

次の最上位のツリーが .aws-sam の下に表示されます。

paciolipacioli

sam build を実行したら、デプロイの準備がは完了しているのでデプロイコマンドを実行する。
公式チュートリありに以下のような記載があった。

チュートリアル: Hello World アプリケーションのデプロイ - AWS Serverless Application Model

HelloWorldFunction may not have authorization defined, Is this okay? [y/N] というプロンプトは、サンプルアプリケーションが認証なしで API Gateway API を設定することを AWS SAM が通知するプロンプトです。サンプルアプリケーションのデプロイ時、AWS SAM は一般に利用可能な URL を作成します。

この通知は、プロンプトに「Y」と応答することで承認できます。認証の設定については、「API Gateway API へのアクセスの制御」を参照してください。

無制限に公開するタイプの API エンドポイントの場合は Y で良くて、何かしら認証をかけたい場合は N という感じなのかな。
API Gateway の認証設定はよくわからないので読み飛ばすけど、以下のページに API Gateway の認証について記載されている。

API Gateway API へのアクセスの制御 - AWS Serverless Application Model

とりあえず、デプロイを実行

sam deploy --guided
# 
# Configuring SAM deploy
# ======================
# 
# 	Looking for config file [samconfig.toml] :  Not found
# 
# 	Setting default arguments for 'sam deploy'
# 	=========================================
# 	Stack Name [sam-app]:
# 	AWS Region [ap-northeast-1]:
# 	#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
# 	Confirm changes before deploy [y/N]:
# 	#SAM needs permission to be able to create roles to connect to the resources in your template
# 	Allow SAM CLI IAM role creation [Y/n]:
# 	#Preserves the state of previously provisioned resources when an operation fails
# 	Disable rollback [y/N]:
# 	HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: Y
# 	Save arguments to configuration file [Y/n]:
# 	SAM configuration file [samconfig.toml]:
# 	SAM configuration environment [default]:
# 
# 	Looking for resources needed for deployment:
# 	Creating the required resources...
# 	Successfully created!
# ...

実行すると、 AWS 上に API Gateway や lambda の関数など、 lambda の API 公開に必要となる AWS リソースが自動的に作成された。

デプロイが終わったら各リソース情報が標準出力にアウトプットされていた。

Key                 HelloWorldFunctionIamRole
Description         Implicit IAM Role created for Hello World function
Value               arn:aws:iam::XXXXXXXXX:role/sam-app-HelloWorldFunctionRole-XXXXXXXXX

Key                 HelloWorldApi
Description         API Gateway endpoint URL for Prod stage for Hello World function
Value               https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/

Key                 HelloWorldFunction
Description         Hello World Lambda Function ARN
Value               arn:aws:lambda:ap-northeast-1:XXXXXXXXX:function:sam-app-HelloWorldFunction-XXXXXXXXX
paciolipacioli

試しに、デプロイされた url にリクエストを投げると、 app.ts 内に記載しているレスポンスがちゃんと返却されてきたので、正常に lambda 関数が稼働している。

curl https://XXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
# {"message":"hello world"}
paciolipacioli

作成したAPIエンドポイントをローカルで実行する。

sam local start-api

暫く待つと docker コンテナが立ち上がるので、立ち上がった後は標準出力に表示された URL を使って、ローカルで lambda 関数にアクセスすることができる。

curl http://127.0.0.1:3000/hello
# {"message":"hello world"}
paciolipacioli

作成した lambda 関数を直接実行する。

sam local invoke
# ...
# START RequestId: 2982643a-df0b-4fb7-9738-41e655d996a6 Version: $LATEST
# END RequestId: 2982643a-df0b-4fb7-9738-41e655d996a6
# REPORT RequestId: 2982643a-df0b-4fb7-9738-41e655d996a6	Init Duration: 0.77 ms	Duration: 841.47 ms	Billed Duration: 842 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
# {"statusCode":200,"body":"{\"message\":\"hello world\"}"}

-e オプションをつけると、 lambda 関数に渡す入力イベントペイロードを渡す事ができるらしい。
入力イベントペイロードってなんやろう・・・。
他の AWS リソースのトリガーで発生するタイプの lambda 関数をローカルで実行する際に利用するものっぽい?