Next.jsのアプリをLambda Web Adapter を利用してホスティングしてみる
参考
セットアップ
next のバージョンを合わせる。
npx create-next-app
npm remove next
npm i next@13.4.2
サンプル完成
next standalone モード
module.exports = {
output: 'standalone',
}
SAM のデプロイ準備
brew install awscli
aws configure
brew tap aws/tap
brew install aws-sam-cli
docker desktop を起動
sam build --use-container
Build Succeeded
デプロイ
Stack Name [sam-app]: next-lambda-streaming
AWS Region [ap-northeast-1]: ap-northeast-1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: y
#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]: n
Capabilities [['CAPABILITY_IAM']]:
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: y
StreamingNextjsFunction Function Url has no authentication. Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]: samconfig.toml
SAM configuration environment [default]: default
Create managed ECR repositories for all functions? [Y/n]: Y
Lambda製
vercel製
どちらも遅い方に引っ張られている。。
公式Example
npx create-next-app@latest nextjs-response-streaming --use-npm --example "https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examples/nextjs-response-streaming"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
compress: true,
output: "standalone", // 追加
images: {
remotePatterns: [
{
protocol: "https",
hostname: "images.unsplash.com"
}
]
}
}
module.exports = nextConfig
静的なアセットをコピーしておく。
下記を追加(publicディレクトリがある場合は)
RUN npm update && npm run build &&\
cp -r -u .next/server .next/standalone/.next &&\
cp -r -u .next/static .next/standalone/.next &&\
cp -r -u public .next/standalone
初回のみ
sam deploy --guided
2回目以降
sam deploy
Stack Name [sam-app]: nextjs-response-streaming
AWS Region [ap-northeast-1]: ap-northeast-1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: y
#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]: n
Capabilities [['CAPABILITY_IAM']]:
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: y
StreamingNextjsFunction Function Url has no authentication. Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]: samconfig.toml
SAM configuration environment [default]: default
Create managed ECR repositories for all functions? [Y/n]: Y
でしてAPI Gateway + Lambdaで動かす意味は?とも思えてきてしまうのが正直なところ。
もちろんPay as you goなプライシングモデルによってコストとしてゼロスタートできることやスケーリングというメリットはあるものの、このソリューションがコンテナイメージで動かす前提であるためDockerfileを書かなければいけないわけで、それならもう普通にAWS Fargateとかでいいじゃないかって思ってしまう。
活用方法
ここまでで、Lambda Web Adapter の仕組みや使い方、また性能的にも十分実用的であることを確認しました。最後に Web Adapter の活用方法をいくつか考えてみました:
既存のコンテナアプリを Lambda 化することで、アイドル時の利用料金や管理の手間を減らす。Lambda Function URL なども組み合わせれば、最小労力で Web アプリを Lambda にデプロイし、ちょっとしたサービスを提供することができそうです。
コンテナアプリをそのまま安価なサーバーレスで動かすことができ、高いスケーラビリティも確保できます。考え方によっては、AWS App Runner と同じような使い方ができると言えるかもしれません。
従来 Lambda 上で動かすことが困難だった HTTP アプリ、例えば nginx や HAProxy などもサーバーレス化できるようになります。実用性に一考の余地はありますが、技術的にはサーバーレスロードバランサーやサーバーレスリバースプロキシといった活用も考えられるでしょう。
今コンテナで動いている Web アプリをそのまま Lambda 上でも動かし、突発的な負荷を Lambda に逃がすというのはいかがでしょうか。通常コンテナより Lambda の方がスケールアウトが速いため、システムのスパイク耐性をより高めることができるでしょう。
lambda-streaming
Lambda context を転送してくれそう。
Lambda Context is an object that Lambda passes to the function handler. This object provides information about the invocation, function, and execution environment. You can find a full list of properties accessible through the Lambda Context here
Lambda Web Adapter forwards this information to the web application in a Http Header named "x-amzn-lambda-context". In the web application, you can retrieve the value of this http header and deserialize it into a JSON object. Check out Express.js in Zip on how to use it.
トラフィックが増えてきたらfargateとか使えば良いかもね。ポーdアビリティ。
既存の Lambda からアダプターを外すことでアプリケーションの可搬性も良くなり、ECS化の必要が出た場合も同じアプリケーションをそのままデプロイ可能となります。
lamda-response