🐕

Next.js 14をAWS Lambdaにデプロイしてサーバーレス化する方法

2024/08/01に公開

環境

  • wsl (Ubuntu)
  • Docker version 27.0.3, build 7d4bcd8
  • Node v18.20.4
  • aws-cli aws-cli/2.17.13 Python/3.11.9 Linux/5.15.153.1-microsoft-standard-WSL2 exe/- x86_64.ubuntu.22

今回作成するネットワーク構成図

ECR リポジトリの作成

今回はプライベートリポジトリを作成しました。

Next.jsのプロジェクトを作成

wsl
cd ~
mkdir next-demo-app
cd next-demo-app
npx create-next-app@latest .

Standaloneモードでビルドできるようにする

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
    output: "standalone",
};

export default nextConfig;

Dockerイメージを作り、ECRにPush

Dockerfileを作成します。

Dockerfile
FROM node:18-alpine AS base

FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi

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
ENV PORT=3000
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]

ECRにPush

wsl
aws sso login
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <XXXXXXXXXXXX>.dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t next-demo-app .
docker tag next-demo-app:latest <XXXXXXXXXXXX>.dkr.ecr.ap-northeast-1.amazonaws.com/next-demo-app:latest
docker push <XXXXXXXXXXXX>.dkr.ecr.ap-northeast-1.amazonaws.com/next-demo-app:latest

うまくいけば以下のように表示されます。

Lambda関数を作成

オプションからコンテナイメージを選びます。
コンテナイメージURIにはECRにPushしたコンテナイメージを選んでください。

メモリを設定

設定->一般設定->編集からメモリを256MBに変更

関数URLを作成

設定->関数 URL->関数 URL を作成をクリック
以下のように設定して保存する。
認証タイプ: AWS_IAM
呼び出しモード: RESPONSE_STREAM

API Gatewayの設定

API を作成->HTTP API構築
統合を追加をクリックしてLambdaを選択
作成したLambda関数を選択し、API名を入力して次へをクリック

ルートの設定

リソースパス$defaultに変更して確認して作成をクリックして作成->をクリック

確認画面

確認

作成したAPI Gatewayのエンドポイントにアクセスできれば問題ないです。

Amplifyを使わずにLambdaにした理由

  • AmplifyにデプロイしたNext.js(SSR)から直接s3にアップロードできない。
  • AmplifyはVPCのサブネット内で実行できないがLambdaはできる。

余談

public/*をs3に置いてCloudFrontを通してアクセスさせるようにすればLambdaの実行回数を大幅に削ることができそうなので、時間があれば記事を書きます。

参考

https://aws.amazon.com/jp/blogs/news/implementing-ssr-streaming-on-nextjs-with-aws-lambda-response-streaming/
https://serverless.co.jp/blog/g30vzpio0ww/

Discussion