【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. 【NextJS】Streaming with Suspense

  2. AWS

    【AWS】AWS SAMを使いCLIでLambda関数をデプロイ(Ty…

  3. 【NextJS】ChatApp with SocketIO

  4. 【NextJS】Hooks-useState(update toget…

  5. 【NextJS】SassとTypescriptでレイアウトを構成

  6. AWS

    【AWS】API Gatewayを使ってみる

最近の記事

  1. AWS
  2. AWS
  3. AWS

制作実績一覧

  1. Checkeys