🦕 deno-lambda触ってみる
右下のボタンからDeployする
Create CompleteしたらCloudFormationを見に行く
「出力」タブにLayerArn
の値が出ているのでこれをコピー
Lambdaの関数の作成に飛び、「一から作成」で関数名を適当に入れ、ランタイムは「ユーザー独自」とする
(日本語訳はもう少しどうにかならんかったんか)
Lambda functionが追加されたら、画面最下部からレイヤーを追加
控えておいたARN
の値を設定
deno-lambdaのリリースページから最新のdeno-lambda-example.zip
をダウンロードし、コードソースにアップロード
適当にログを出すよう書き換えてDeploy
Testを実行すると良い感じのResponseが帰ってくる🦕
「モニタリング」タブから「CloudWatchのログを見る」でログを確認、こちらにもちゃんと表示されている
続いてServerless Frameworkの使用を試みる serverless
はbrew
で導入済み
❯ sls create --template aws-nodejs --path sls-hello-deno
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/kawarimidoll/ghq/github.com/kawarimidoll/sls-hello-deno"
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v2.46.0
-------'
Serverless: Successfully generated boilerplate for template: "aws-nodejs"
❯ cd sls-hello-deno
❯ ls -A1
.npmignore
handler.js
serverless.yml
コンパイルするためにserverless-scriptable-plugin
を導入する
sls plugin install --name serverless-scriptable-plugin
するとserverless.yml
に自動で追記してくれるが、これを使うとpackage.json
が作られてしまうのでやめておく(denoのプロジェクトにpackage.json
を置きたくない…)
❯ yarn global add serverless-scriptable-plugin
yarn global v1.22.10
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
warning "serverless-scriptable-plugin@1.2.1" has no binaries
✨ Done in 3.30s.
serverless.yml
の設定を追加 コメントはすべて省略
service: sls-hello-deno
frameworkVersion: "2"
provider:
name: aws
- runtime: node-12.x
+ runtime: provided.al2
lambdaHashingVersion: 20201221
+ package:
+ exclude:
+ - .deno_dir/gen/file
functions:
hello:
handler: handler.hello
events:
- http:
- path: /users/create
+ path: /hello
method: get
+ plugins:
+ - serverless-scriptable-plugin
+ custom:
+ scriptHooks:
+ before:package:createDeploymentArtifacts: DENO_DIR=.deno_dir deno cache api/hello.ts && cp -R .deno_dir/gen/file/$PWD/ .deno_dir/LAMBDA_TASK_ROOT
しかしsls print
したらエラー
❯ sls print
Serverless Error ----------------------------------------
Serverless plugin "serverless-scriptable-plugin" not found. Make sure it's installed and listed in the "plugins" section of your serverless config file.
pluginが見えていない…?
brew
ではなくyarn global
で入れ直したら実行できた
❯ brew uninstall serverless
Uninstalling /opt/homebrew/Cellar/serverless/2.46.0... (20,301 files, 124.7MB)
❯ yarn global add serverless serverless-scriptable-plugin
yarn global v1.22.10
[1/4] 🔍 Resolving packages...
(略)
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
warning "serverless > @serverless/components > inquirer-autocomplete-prompt@1.3.0" has unmet peer dependency "inquirer@^5.0.0 || ^6.0.0 || ^7.0.0".
[4/4] 🔨 Building fresh packages...
success Installed "serverless@2.46.0" with binaries:
- serverless
- sls
warning "serverless-scriptable-plugin@1.2.1" has no binaries
✨ Done in 52.98s.
また、serverless.yml
のpackage.include
とpackage.exclude
はdeprecatedらしいのでpackage.patterns
に切り替える
❯ sls print
service:
name: sls-hello-deno
frameworkVersion: '2'
provider:
stage: dev
region: us-east-1
name: aws
runtime: provided.al2
lambdaHashingVersion: '20201221'
versionFunctions: true
package:
patterns:
- '!.deno_dir/gen/file'
functions:
hello:
handler: handler.hello
events:
- httpApi:
path: /hello
method: get
name: sls-hello-deno-dev-hello
plugins:
- serverless-scriptable-plugin
custom:
scriptHooks:
before:package:createDeploymentArtifacts: >-
DENO_DIR=.deno_dir deno cache api/hello.ts && cp -R .deno_dir/gen/file/$PWD/
.deno_dir/LAMBDA_TASK_ROOT
とりあえず公式のhello.tsを参考にファイルを作成
import {
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
Context,
} from "https://deno.land/x/lambda/mod.ts";
export type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context };
import {
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
Context,
} from "../deps.ts";
// deno-lint-ignore require-await
export async function handler(
event: APIGatewayProxyEventV2,
_context: Context,
): Promise<APIGatewayProxyResultV2> {
return {
statusCode: 200,
headers: { "content-type": "text/html;charset=utf8" },
body: JSON.stringify(
{
message: `Welcome to deno ${Deno.version.deno} 🦕`,
input: event,
},
null,
2,
),
};
}
いきなりデプロイするのではなくdocker-lambdaを使ってみる
deno-lambdaのリリースページからdeno-lambda-layer.zip
をダウンロードして展開、今回のプロジェクトディレクトリに配置する
❯ tree
.
├── .gitignore
├── api
│ └── hello.ts
├── deno-lambda-layer
│ ├── .deno_dir
│ │ ├── deps
│ │ │ └── https
│ │ │ └── deno.land
│ │ │ └── x
│ │ │ └── lambda
│ │ │ ├── mod.ts
│ │ │ └── types.d.ts
│ │ ├── gen
│ │ └── LAMBDA_TASK_ROOT
│ │ ├── hello.ts.buildinfo
│ │ ├── hello.ts.js
│ │ ├── hello.ts.meta
│ │ ├── mod.ts.js
│ │ └── mod.ts.meta
│ ├── bin
│ │ └── deno
│ ├── bootstrap
│ └── hello.ts
├── deps.ts
└── serverless.yml
READMEのdocker-lambdaの項目にあるサンプルスクリプトを利用し、今回の構成に沿うようLAYER_DIR
およびhandler
の部分を調整して実行
❯ docker run -it --rm -v "$PWD":/var/task:ro,delegated -v "$PWD"/deno-lambda-layer:/opt:ro,delegated lambci/lambda:provided.al2 api/hello.handler '{}'
(略)
{"statusCode":200,"headers":{"content-type":"text/html;charset=utf8"},"body":"{\n \"message\": \"Welcome to deno 1.11.0 🦕\",\n \"input\": {}\n}"}
api/hello.ts
で定義したhandler()
を実行できた👍
"stay-open" API mode
も試してみる
❯ docker run -e DOCKER_LAMBDA_STAY_OPEN=1 -p 9001:9001 -it --rm -v "$PWD":/var/task:ro,delegated -v "$PWD"/deno-lambda-layer:/opt:ro,delegated lambci/lambda:provided.al2 api/hello.handler
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
Lambda API listening on port 9001...
別ターミナルを開いてaws-cli
からリクエスト実行
なおaws-cli
がバージョン2の場合は--cli-binary-format raw-in-base64-out
オプションが必要になるので注意
❯ aws lambda invoke --endpoint http://localhost:9001 --cli-binary-format raw-in-base64-out --no-sign-request --function-name deno-func --payload '{"message":"hello from aws-cli"}' output.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
❯ cat output.json
{"statusCode":200,"headers":{"content-type":"text/html;charset=utf8"},"body":"{\"message\":\"Welcome to deno 1.11.0 🦕\",\"input\":{\"message\":\"hello from aws-cli\"}}"}
ローカルでの挙動は問題なさそう✨
ではネットの海へ
❯ sls deploy -v
Running command: DENO_DIR=.deno_dir deno cache api/hello.ts && cp -R .deno_dir/gen/file/$PWD/ .deno_dir/LAMBDA_TASK_ROOT
Download https://deno.land/x/lambda/mod.ts
Warning Implicitly using latest version (1.11.0) for https://deno.land/x/lambda/mod.ts
Download https://deno.land/x/lambda@1.11.0/mod.ts
Download https://deno.land/x/lambda@1.11.0/types.d.ts
Check file:///Users/kawarimidoll/ghq/github.com/kawarimidoll/sls-hello-deno/api/hello.ts
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
(略)
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service sls-hello-deno.zip file to S3 (32.69 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
(略)
Serverless: Stack update finished...
Service Information
service: sls-hello-deno
stage: dev
region: us-east-1
stack: sls-hello-deno-dev
resources: 11
api keys:
None
endpoints:
GET - https://xxxxx.execute-api.us-east-1.amazonaws.com/hello
functions:
hello: sls-hello-deno-dev-hello
layers:
None
Stack Outputs
(略)
デプロイには成功
しかしLayerが設定されていないので実行できない…
serverless.yml
を修正した
service: sls-hello-deno
frameworkVersion: "2"
provider:
name: aws
runtime: provided.al2
lambdaHashingVersion: 20201221
package:
patterns:
- "!.deno_dir/gen/file"
functions:
hello:
handler: api/hello.handler
+ layers:
+ - !GetAtt Deno.Outputs.LayerArn
+ memorySize: 128
+ description: Say hello and show deno version
events:
- httpApi:
path: /hello
method: get
+ resources:
+ Transform: AWS::Serverless-2016-10-31
+ Resources:
+ Deno:
+ Type: AWS::Serverless::Application
+ Properties:
+ Location:
+ ApplicationId: arn:aws:serverlessrepo:us-east-1:390065572566:applications/deno
+ SemanticVersion: 1.11.0
plugins:
- serverless-scriptable-plugin
custom:
scriptHooks:
before:package:createDeploymentArtifacts: DENO_DIR=.deno_dir deno cache api/hello.ts && cp -R .deno_dir/gen/file/$PWD/ .deno_dir/LAMBDA_TASK_ROOT
resources
でCloudFormationの設定を行う
これは公式のサンプルそのまま
特にTransform: AWS::Serverless-2016-10-31
はアプリケーションごとのバージョニングかと思ったらAWS SAMのおまじないだった
この辺はSAM用のテンプレートとも同じ書き方になっている
+ resources:
+ Transform: AWS::Serverless-2016-10-31
+ Resources:
+ Deno:
+ Type: AWS::Serverless::Application
+ Properties:
+ Location:
+ ApplicationId: arn:aws:serverlessrepo:us-east-1:390065572566:applications/deno
+ SemanticVersion: 1.11.0
これでzipファイルを使った場合と同じようにCloudFormationでArnが出力される
そしてそれを!GetAtt
してfunctionのレイヤーに適用している
functions:
hello:
handler: api/hello.handler
+ layers:
+ - !GetAtt Deno.Outputs.LayerArn
これでsls deploy
するとレイヤーが作成される
sls deploy
の結果に出たエンドポイントへアクセスするとちゃんとレスポンスが帰ってきた!
❯ curl https://xxx.execute-api.us-east-1.amazonaws.com/hello
{"message":"Welcome to deno 1.11.0 🦕","input":{"version":"2.0","routeKey":"GET /hello", ...
いったん基本は完成したので記録
ディレクトリ構成はこんな感じ
提供されているdocker用のzipファイルにはいろいろ入っているがこれ以外は不要ぽい
❯ tree
.
├── .gitignore
├── api
│ └── hello.ts
├── deno-lambda-layer
│ ├── bin
│ │ └── deno
│ └── bootstrap
├── deps.ts
├── README.md
└── serverless.yml
tsファイルの内容は以下の通り
import {
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
Context,
} from "https://deno.land/x/lambda@1.11.0/mod.ts";
export type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context };
import {
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
Context,
} from "../deps.ts";
// deno-lint-ignore require-await
export async function handler(
event: APIGatewayProxyEventV2,
_context: Context,
): Promise<APIGatewayProxyResultV2> {
console.log("[hello] got request!");
return {
statusCode: 200,
headers: { "content-type": "text/html;charset=utf8" },
body: JSON.stringify({
message: `Welcome to deno ${Deno.version.deno} 🦕`,
input: event,
}),
};
}
Postmanでも疎通確認
今回はevent
をそのまま返してしまったけど現実的にはevent.body.xxx
を取り出して使う感じかな
pushしてから気づいたけどdeno-lambda-layerのdeno実行ファイルはサイズが大きくてgithubから怒られるのでgitignoreしたほうが良さげ
❯ zip -r deno-lambda-layer.zip deno-lambda-layer
❯ echo deno-lambda-layer/ >> .gitignore
❯ git rm --cached -r deno-lambda-layer/
rm 'deno-lambda-layer/bin/deno'
rm 'deno-lambda-layer/bootstrap'