【AWS】Deploy Serverless NextJS app with AWS Lambda Web Adapter using AWS SAM

AWS

1. 概要

前回はバックエンド側のAPIをSAMで環境毎にデプロイする内容でした。今回はNextJSアプリをServerlessのLambdaにデプロイする内容となります。

  • NextJSアプリは簡易なTodoアプリです。

こちらの記事にインスピレーションを受けたので合わせて読んで頂ければ幸いです。

NextJSのソースコード以外はほぼ下記のままです。

2. Nodeのインストール

こちらを参考

3. プロジェクトを作成

3-1. こちらを参考

4. ソースコード

※簡易Todoアプリ

4-1. src/app/page.tsx

"use client";

import { ChangeEvent, MouseEvent, KeyboardEvent, useState } from "react";

export type Todo = {
  id: number;
  content: string;
};

export default function Home() {
  const [text, setText] = useState<string>("");
  const [todos, setTodos] = useState<Todo[]>([]);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    e.preventDefault();
    setText(e.currentTarget.value);
  };

  const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    applyData();
  };

  const keyDownHandler = (e: KeyboardEvent<HTMLInputElement>) => {
    if (e.nativeEvent.isComposing || e.key !== "Enter") return;
    applyData();
    e.currentTarget.focus();
  };

  const applyData = () => {
    if (text.length == 0) return;
    const todo: Todo = { id: ++todos.length, content: text };
    const newTodos: Todo[] = [...todos, todo].filter(
      (todo) => todo != undefined
    );
    setTodos(newTodos);
    setText("");
  };

  const removeData = (e: MouseEvent<HTMLAnchorElement>, todoId: number) => {
    e.preventDefault();
    const newTodos: Todo[] = [...todos].filter((todo) => todo.id != todoId);
    setTodos(newTodos);
  };

  return (
    <div>
      <input
        type="text"
        value={text}
        onChange={(e) => handleChange(e)}
        onKeyDown={keyDownHandler}
        autoFocus={true}
      />
      <button onClick={handleClick}>Register</button>
      <br />
      Todo list
      <ul>
        {todos.map((todo: Todo, idx: number) => (
          <li key={idx}>
            {todo.content}(
            <a
              href="#"
              onClick={(e: MouseEvent<HTMLAnchorElement>) =>
                removeData(e, todo.id)
              }
            >
              X
            </a>
            )
          </li>
        ))}
      </ul>
    </div>
  );
}

5. AWSアカウントにサインアップ

5-1. 前提条件

6. AWSアクセスキーの取得

6-1. AWSアクセスキーの取得

7. AWS CLI のインストール

7-1. インストール

8. AWS SAM CLIのインストール

8-1. インストール

9. 起動シェルを作成

9-1. run.sh

#!/bin/bash -x

[ ! -d '/tmp/cache' ] && mkdir -p /tmp/cache

exec node server.js

10. Dockerfileを作成

10-1. Dockerfile

FROM public.ecr.aws/docker/library/node:20.9.0-slim as builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

FROM public.ecr.aws/docker/library/node:20.9.0-slim as runner
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.0 /lambda-adapter /opt/extensions/lambda-adapter
ENV PORT=3000 NODE_ENV=production
ENV AWS_LWA_ENABLE_COMPRESSION=true
WORKDIR /app
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/run.sh ./run.sh
RUN ln -s /tmp/cache ./.next/cache

RUN chmod +x ./run.sh
CMD exec ./run.sh

11. template.yamlを作成

11-1. template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  serverless-nextjs-demo

  Sample SAM Template for serverless-nextjs-demo

Globals:
  Function:
    Timeout: 10

Resources:
  NextjsFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: /
      MemorySize: 256
      PackageType: Image
      Architectures:
        - x86_64
      Events:
        RootEvent:
          Type: HttpApi
          Properties:
            Path: /
            Method: any
        ProxyEvent:
          Type: HttpApi
          Properties:
            Path: /{proxy+}
            Method: any
    Metadata:
      DockerTag: v1
      DockerContext: ./
      Dockerfile: Dockerfile

Outputs:
  NextjsFunctionURL:
    Description: "API Gateway endpoint URL for Next.js"
    Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/"
  • 「samconfig.toml」は「sam deploy」後、作成される。
    • 「sam deploy」前に最初から作成しても良い。
    • 下記は自動作成後

version = 0.1
[default.deploy.parameters]
stack_name = "serverless-nextjs-demo"
resolve_s3 = true
s3_prefix = "serverless-nextjs-demo"
region = "ap-northeast-1"
capabilities = "CAPABILITY_IAM"
image_repositories = ["NextjsFunction=123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/serverlessnextjsdemoe3456789/nextjsfunction23456789repo"]

12. NextJSのoutputを指定

12-1. next.config.js

const nextConfig: NextConfig = {
  output: "standalone",
};

12-2. ディレクトリ構造

.
├── Dockerfile
├── README.md
├── eslint.config.mjs
├── next-env.d.ts
├── next.config.ts
├── package-lock.json
├── package.json
├── postcss.config.mjs
├── public
│   ├── file.svg
│   ├── globe.svg
│   ├── next.svg
│   ├── vercel.svg
│   └── window.svg
├── run.sh
├── src
│   └── app
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx
│       └── page.tsx
├── tailwind.config.ts
├── template.yaml
└── tsconfig.json

3 directories, 21 files

13. アプリケーションを構築

13-1. build

sam build

14. アプリケーションをAWS クラウドにデプロイ

14-1. deploy

sam deploy --guided
.
.
.
CloudFormation outputs from deployed stack
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                          
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 NextjsFunctionURL                                                                                                                            
Description         API Gateway endpoint URL for Next.js                                                                                                         
Value               https://a1b2c3d4e5.execute-api.ap-northeast-1.amazonaws.com/                                                                                 
------------------------------------------------------------------------------------------------------------------------------------------------------------------


Successfully created/updated stack - serverless-nextjs-demo in ap-northeast-1

15. アプリケーションを確認

15-1. エンドポイントの値を取得

  • 上記14-1ログより「Outputs」を探す
    • Key
      • NextjsFunctionURL
    • Value
      • https://a1b2c3d4e5.execute-api.ap-northeast-1.amazonaws.com/
      • これがエンドポイント

15-2. 画面で確認

16. Management Consoleで確認

16-1. 画面で確認

17. AWSクラウドからアプリケーションを削除

※必要に応じ削除

sam delete --stack-name serverless-nextjs-demo

18. 備考

今回はNextJSアプリをServerlessのLambdaにデプロイする内容でした。

19. 参考

  1. AWS Serverless Application Model (AWS SAM) とは何ですか? – AWS Serverless Application Model (amazon.com)
  2. aws-lambda-web-adapter/examples/nextjs at main · awslabs/aws-lambda-web-adapter · GitHub
  3. Introduction | Next.js

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. AWS

    【AWS】Amazon DynamoDBを使ってみる(Manageme…

  2. AWS

    【AWS】AWS Step Functionsを触ってみる

  3. 【NextJS】Error Handling

  4. 【NextJS】View and Download PDF

  5. AWS

    【AWS】Amazon DynamoDBを使ってみる(CLI、Part…

  6. 【NextJS】VSCodeにGemini Code Assistを連…

最近の記事

  1. AWS
  2. AWS

制作実績一覧

  1. Checkeys