Next.js を サーバーレス(AWS Lambda)で動かす
Next.js を AWS Lambda で動かすための設定などについて説明します。
事前準備
AWS SAM (AWS Serverless Application Model) を用いてサーバーレス環境を構築していきます。
事前に、AWS SAM CLI をインストールしておきます。
概要
すでに作成済みの Next.js アプリをベースに、サーバーレス環境を構築していきます。
Dockerfile の追加
template.yaml の追加
samconfig.toml の追加(任意)
Next.js の Standalone モード(推奨)
早速、デプロイして動かしてみたいという方は、下記のリポジトリを用意してますので、git clone してみてください。
Dockerfile の追加
Next.js のビルドに加えて、Lambda Adapter のインストールが必要になります。インストールは簡単で以下の行を追加するだけです。
# Dockerfile
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.0 /lambda-adapter /opt/extensions/lambda-adapter
# Dockerfile
FROM node:20-bullseye-slim AS base
FROM base AS deps
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn --frozen-lockfile
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
FROM base AS runner
# Install Lambda Web Adapter
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.0 /lambda-adapter /opt/extensions/lambda-adapter
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
template.yaml の追加
下記のように template.yaml を記述します。
ポイントをざっと列挙すると以下のようになります。
公式ドキュメントに詳しい説明があります。
PackageType を Image に
Metadata.Dockerfile など Docker 関連の設定を追加
環境変数 AWS_LWA_INVOKE_MODE に response_stream を指定
FunctionUrlConfig.InvokeMode に RESPONSE_STREAM を指定
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
nextjs-lambda
SAM Template for Next.js on AWS
Parameters:
StackFamily:
Type: String
Default: nextjs-lambda-app
Globals:
Function:
Timeout: 3
Tracing: Active
Resources:
NextFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
MemorySize: 512
Timeout: 30
Architectures:
- x86_64
Environment:
Variables:
AWS_LWA_INVOKE_MODE: response_stream
DEBUG: "*"
FunctionUrlConfig:
AuthType: NONE
InvokeMode: RESPONSE_STREAM
Metadata:
DockerTag: v1
DockerContext: .
Dockerfile: Dockerfile
Outputs:
NextFunction:
Value: !GetAtt NextFunction.Arn
Export:
Name: !Sub "${StackFamily}-next-function-arn"
NextFunctionUrl:
Value: !GetAtt NextFunctionUrl.FunctionUrl
Export:
Name: !Sub "${StackFamily}-next-function-url"
samconfig.toml の追加(任意)
samconfig.toml は SAM CLI コマンドのパラメータを記述できるファイルですが、初回デプロイ時に作成されるので、あらかじめ作成しなくてもOKです。
Next.js の Standalone モード(推奨)
前述の公式ドキュメントにも記載がありますが、AWS Lambda ではデプロイされるパッケージのサイズに 250MB のクォータが設けられているので、Standalone モードに設定します。
下記のように next.config.mjs の output に 'standalone' を指定します。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone'
};
export default nextConfig;
デプロイ
下記のように sam deploy --guided すると、デプロイできるはずです。
# bash
$ sam deploy --guided --profile=${AWS_PROFILE}
デプロイが完了すると、下記のように Lambda URL が出力されるのでアクセスしてみます。
CloudFormation outputs from deployed stack
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key EcrFrontend
Description -
Value nextjs-lambda-app/frontend
Key NextFunctionUrl
Description -
Value https://{LAMBDA_URL_ID}.lambda-url.{AWS_REGION}.on.aws/
Key NextFunction
Description -
Value arn:aws:lambda:{AWS_REGION}:{AWS_ACCOUNT_ID}:function:nextjs-lambda-app-NextFunction-{FUNCTION_ID}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - nextjs-lambda-app in {AWS_REGION}
下記のように、トップページが表示されればOKです。
おわりに
Node.js のサーバーを長期間稼働させていると動作が不安定になるイメージがあった(あくまで個人の感想です)ので、SSRを避けてきました。
が、サーバーレスで起動する分にはその問題はありませんし、起動時間も問題なさそうなので、最近は、小規模なアプリの場合はサーバーサイドも、Next.js の Server Actions として実装するようにしています。
何よりサーバーレスにしておくと、サーバーを常時起動するよりも低コストで運用できるのが魅力ですね。
何か質問などありましたら、@yields_llc にコメントいただければ幸いです。
ではでは。