AWS Lambda Web Adapterを使ってDeno + HonoをLambdaで動かす
はじめに
Hono の公式ドキュメントにはAWS Lambda での使用方法が書かれています。
ただ、Node.js や Bun でのデプロイ方法はありましたが、Deno での方法がありませんでした。
Deno + Hono を AWS Lambda で動かすことができないか?と調べてたところ、AWS Lambda Web Adapterを使えばいけそうだったので、試してみました。
結果、動作確認ができたので、その方法等を共有します。
AWS Lambda Web Adapter とは
Lambda Web Adapterは 『VM やコンテナ用で作られたウェブアプリを Lambda で動かすためのツール』 です。
Dockerfile に
COPY /lambda-adapter /opt/extensions/lambda-adapter
を追加することで、Lambda のコンテナランタイムで Docker イメージを動かすことがでくるようになります。
AWS Lambda Web Adapter は何をしているのか
AWS Lambda Web Adapter は Lambda と統合先との間で以下のように動作しているようです。
- API Gateway 等から Lambda ランタイムがイベントを受信
- Web Adapter がイベントをパースし、HTTP リクエストに変換し、Web アプリのプロセスに HTTP に転送
- Web アプリがリクエストを処理し、HTTP でレスポンス
- Web Adapter が API Gateway 等が受け取る形式に変換し、Lmabda ランタイムへ返還
- Lambda ランタイムが API Gateway 等にレスポンスを返還
方法
私がプロジェクト作成からデプロイまでやったこととしては以下です。
- VS Code DevContainer + Docker で Deno + Hono 開発環境を構築
- Github Actions で Docker イメージのビルドと ECR へのプッシュ
- AWS CDK で インフラ構築
本記事では作業の中でも特徴的だった
- Dockerfile の記述
- リッスンポート
- AWS CDK でのインフラ構築
について記載します。
Dockerfile
FROM denoland/deno:1.46.2
COPY /lambda-adapter /opt/extensions/lambda-adapter
WORKDIR /app
COPY deno.jsonc deno.lock main.ts routers.ts /app/
EXPOSE 8080
RUN deno cache ./main.ts
CMD ["deno", "task", "start"]
AWS Lambda Web Adapter を使うために、Dockerfile に
COPY /lambda-adapter /opt/extensions/lambda-adapter
を定義しています。
また、依存関係を Docker イメージに詰めておかないと、Lambda 起動時に
failed caching npm package ...
というエラーが発生するので、依存関係も Docker イメージに詰めています。
RUN deno cache ./main.ts
リッスンポート
Lambda Web Adapter は8080
ポートにトラフィックを送信します。
ポートはAWS_LWA_PORT
という環境変数で変更できます。
AWS CDK によるインフラ構築
AWS CDKは、AWS のインフラストラクチャをコードで管理するためのフレームワークです。
本記事では専用の IAW ユーザや ECR リポジトリ、ECR への Docker イメージは作成&デプロイ済みであること前提とします。
AWS CDK でのインフラ構築は以下のようになります。
TypeScript で記述しています。
import { App, Duration, Stack, StackProps } from "aws-cdk-lib";
import lambda from "aws-cdk-lib/aws-lambda";
import ecr from "aws-cdk-lib/aws-ecr";
import iam from "aws-cdk-lib/aws-iam";
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
import apiGateway from "aws-cdk-lib/aws-apigatewayv2";
export class AppStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
const ecrRepoArn = ecr.Repository.fromRepositoryArn(
this,
"test-deno-hono",
"arn:aws:ecr:ap-northeast-1:123456789000:repository/test-deno-hono"
);
const iamRole = new iam.Role(this, "TestDenoHonoRole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
),
],
});
const testDenoHonoLambda = new lambda.DockerImageFunction(
this,
"TestDenoHono",
{
code: lambda.DockerImageCode.fromEcr(ecrRepoArn),
memorySize: 512,
timeout: Duration.seconds(180),
role: iamRole,
}
);
const integration = new HttpLambdaIntegration(
"TestDenoHonoApiIntegration",
testDenoHonoLambda
);
new apiGateway.HttpApi(this, "TestDenoHonoApi");
}
}
new AppStack(new App(), "test-deno-hono-lambda-stack", {
env: { region: "ap-northeast-1", account: "123456789000" },
});
実行は以下で実行できます。
deno run --allow-all npm:aws-cdk deploy --app 'deno run --allow-all ファイル名' -v
性能面について
レイテンシ、コールドスタート、メモリ使用量などの性能面については今回検証できていません。
以下の記事に性能面について Node.js + Express での比較が書かれているので、参考にしてください。
おわりに
AWS Lambda Web Adapter を使うことで、Deno + Hono を AWS Lambda で動かすことができました。
Deno も Hono もまだまだ新興な技術なので、今後、もっと良い Aws Lambda + Deno + Hono 環境ができることを期待します。
参考記事
Discussion