Next.js を AWS Amplify にTerraformを使ってデプロイする際の注意点

タイトルの通り、Nextjsで作成したWEBアプリをterraformでAWS Amplifyにホスティングさせる際、躓いた点があったので共有したいと思います。

# 各サービスの簡単な説明
## Nextjs
Reactベースのjs,tsフレームワークでWEB開発に用いられるフレームワークです。サーバサイドでのレンダリングSSRや静的なアプリの作成SSGなどが特徴的です。

## AWS Amplify
AWSのサービスの一つでWEBやモバイルアプリを高速に開発するためのUIやライブラリ、インフラを提供してくれます。AWSの他のサービスとの連携がやりやすいです。類似サービスにGCPのFirebaseがあげられます。
今回はAmplifyの中でもhosting機能を使用しました。

## Terraform
IaCと呼ばれる技術の一つで、AWSをはじめとしたインフラをコードを書くことで構築できます。今回はAWS AmplifyをTerraformで構築しました。
TerraformのAmplify公式ページはこちら
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/amplify_app

## 躓いたポイント1 ~Node.jsのバージョン~
AWS Amplify のホスティングでは、デフォルトでは自動的にAmplify側で設定されたコンテナイメージをベースとしてアプリがデプロイされます。このときのコンテナのNodeのバージョンが違うためにデプロイが失敗していました。
AWSコンソール上ではプロビジョン→構築→デプロイという順番でホスティングが行われますが、私の場合、これらは成功した扱いになっていました。
しかし、いざURLにアクセスしてみるとページが見つからないという返答が帰ってきます。
Nodeのバージョンを指定するためには以下のようなTerraformのコードを書きます。
```terraform:amplify.tf
resource "aws_amplify_app" "app_name" {
    name     = "app_name"
    repository = local.repository
    iam_service_role_arn = aws_iam_role.amplify_role.arn
    environment_variables = {
    "_CUSTOM_IMAGE" = "node:20"
  }

    build_spec = <<-EOT
    version: 1
    applications:
      - frontend:
          phases:
            preBuild:
              commands:
                - npm ci --cache .npm --prefer-offline
            build:
              commands:
                - npm run build
          artifacts:
            baseDirectory: .next
            files:
              - '**/*'
          cache:
            paths:
              - .next/cache/**/*
              - .npm/**/*
        appRoot: my_folder
  EOT

}
```

environment_variableに使用するイメージを指定します。

## 躓いたポイント2 ~platform~
amplifyではplatformという属性に"WEB"または、"WEB_COMPUTE"という値を設定できます。Nextjs では SSRとSSGという二つのレンダリング法がサーバ側のレンダリングとして存在しますが、SSRを使用する場合は"WEB_COMPUTE"という値を指定する必要があるようです。

```terraform:amplify.tf
resource "aws_amplify_app" "app_name" {
    name     = "app_name"
    repository = local.repository
    platform = "WEB_COMPUTE"
    iam_service_role_arn = aws_iam_role.amplify_role.arn
    environment_variables = {
    "_CUSTOM_IMAGE" = "node:20"
  }

    build_spec = <<-EOT
    version: 1
    applications:
      - frontend:
          phases:
            preBuild:
              commands:
                - npm ci --cache .npm --prefer-offline
            build:
              commands:
                - npm run build
          artifacts:
            baseDirectory: .next
            files:
              - '**/*'
          cache:
            paths:
              - .next/cache/**/*
              - .npm/**/*
        appRoot: my_folder
  EOT

}
```

## 躓いたポイント3 ~monorepoの指定~
Amplifyではgithubからの連携の場合、自動でビルドのための設定ファイルを生成してくれますが、その際にビルドを行うディレクトリがルートでない場合(モノレポ構成など)、設定ファイルでappRootの指定と環境変数に"AMPLIFY_MONOREPO_APP_ROOT"という値でビルドを行うディレクトリを設定する必要があります。環境変数の方はTerraform上でenvironment_variablesブロックを指定しない場合、自動で設定ファイルから環境変数をセットしてくれますが、今回はコンテナイメージの指定のために環境変数をTerraform内で使用しているので明示的に設定してあげる必要があります。

```terraform:amplify.tf
resource "aws_amplify_app" "app_name" {
    name     = "app_name"
    repository = local.repository
    platform = "WEB_COMPUTE"
    iam_service_role_arn = aws_iam_role.amplify_role.arn
    environment_variables = {
    "_CUSTOM_IMAGE" = "node:20"
    "AMPLIFY_MONOREPO_APP_ROOT" = "my_folder"
  }

    build_spec = <<-EOT
    version: 1
    applications:
      - frontend:
          phases:
            preBuild:
              commands:
                - npm ci --cache .npm --prefer-offline
            build:
              commands:
                - npm run build
          artifacts:
            baseDirectory: .next
            files:
              - '**/*'
          cache:
            paths:
              - .next/cache/**/*
              - .npm/**/*
        appRoot: my_folder
  EOT

}
```

# 終わりに
AWS Amplifyは簡単にアプリのデプロイができ非常に便利だと感じました。一方でTerraformでの連携に関しては公式ドキュメントなどが主な情報源になるのでしっかり読み進めていく必要があります。簡単にアプリのデプロイや削除などを行えるAmplifyと柔軟にインフラを管理できるTerraformの相性は良いと思います。ブランチを自動で接続したりする機能などもTerraformで管理できるようなのでもっと調べることがありそうです。
また、Amplifyはその他のAWSサービスを裏で使用する形であり、それらに個別のコストがかかります。今回はホスティングだけなのでコストはホスティング専用の料金体系の身になりますが、他のAmplifyの機能を使う場合はコスト管理にも気を付ける必要がありそうです。