Next.jsをLambdaにデプロイする方法についての説明。

今回のプロジェクトは cdk用ディレクトリ next-cdk の中に、Next.jsのプロジェクトディレクトリ next-app が存在する構成です。

next-cdk --- package.json (CDK用)
          |- Dockerfile   (デプロイ用)
          |- lib -------- next-cdk-stack.ts
          |
          |- next-app --- package.json (Next.js用)
                       |- .next        (ビルド成果物用)
                       |- src --- app
プロジェクトの作成方法は以下を参照

Dockerイメージでデプロイ

以下を参考にDockerイメージによるデプロイを行います。

Next.jsをLambdaで動作させる場合、AWS Lambda Web Adapterが必要となります。 AWS Lambda Web Adapter は、Lambda ランタイムが受け取ったイベントをHTTPリクエストに変換し、Webサーバーにリクエストします。 Dockerイメージでデプロイする場合、Dockerfileに以下を追加する必要があります。

COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.0 /lambda-adapter /opt/extensions/lambda-adapter

例 Dockerfile

#  以下を参考にして作成
# https://aws.amazon.com/jp/blogs/news/implementing-ssr-streaming-on-nextjs-with-aws-lambda-response-streaming/
FROM node:20-alpine AS base

FROM base AS builder
RUN apk add --no-cache libc6-compat
WORKDIR /next-app
COPY ./next-app/node_modules ./node_modules

COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.0 /lambda-adapter /opt/extensions/lambda-adapter

ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
WORKDIR /next-app
COPY ./next-app/public ./public
COPY ./next-app/.next/standalone ./
COPY ./next-app/.next/static ./.next/static

CMD ["node", "server.js"]

CDKスタック

ここではLambdaでの動作確認を簡単にするため、Lambda Function URLs(関数URL)を使って直接アクセスできるようにします。

DockerイメージでLambdaにデプロイする場合、DockerImageFunctionクラスを使います。 fromImageAssetでDockerfileのあるディレクトリを指定します。

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import path = require('path');

export class NextCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    this.createLambda();
  }

  private createLambda() {
    const lambdaDockerFunction = new lambda.DockerImageFunction(this, 'NextCdkDockerFunctionn', {
      code: lambda.DockerImageCode.fromImageAsset(path.resolve(__dirname, '../')),
      functionName: 'NextCdkDockerFunctionn',
    });
      
    const funcUrl = lambdaDockerFunction.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
      cors: {
        allowedMethods: [lambda.HttpMethod.ALL],
        allowedOrigins: ["*"],
      },
    });

    new cdk.CfnOutput(this, 'FuntionUrl', {
      value: funcUrl.url
    });
  }
}

デプロイが成功するとDockerイメージは Amazon ECR (Elastic Container Registry)に登録されます。

参考

ビルド+デプロイ用コマンド

Next.jsの実行環境は npm run build コマンドでビルドしてその成果物をDockerイメージにコピーすることで作成します。 そのため、CDK用package.jsonにビルドとデプロイをまとめて実行するコマンドを追加します。また、CDKのDIFFコマンドも追加しておきます。

例 CDK用package.jsonのscripts

  "scripts": {
    "cdk": "cdk",
    "cdk:diff": "cd next-app && npm run build && cd ../ && cdk diff",
    "cdk:deploy": "cd next-app && npm run build && cd ../ && cdk deploy"
  },

最新のビルドとデプロイを行う場合、以下のDIFFコマンドを先に実行して差分やエラーが無いかを確認しておきます。

npm run cdk:diff

問題なければ以下で最新のビルドとデプロイを実行します。

npm run cdk:deploy