見出し画像

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.js には本番環境で必要となるファイルのみをまとめて出力する Standalone モード があります。これによりビルド成果物のサイズを大幅に削減できます。なお、AWS Lambda ではデプロイされるパッケージのサイズに 250MB のクォータが設けられており、注意が必要です。

Next.js を Standalone モードでビルドすると、./next 配下に成果物が展開されます。

Next.js 13 の SSR Streaming を AWS Lambda Response Streaming で実装する方法 | Amazon Web Services ブログ

下記のように 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 にコメントいただければ幸いです。
ではでは。

参考リンク