【Terraform】AmplifyでNext.jsのSSRアプリをデプロイ
やりたいこと
Next.jsを使ってwebアプリのフロントエンドを作ったので、Terraformを使ってAmplifyでデプロイしてみます。
なぜAmplifyなのか
SSRで構築したかったことが第一にあります。
Amplify以外だとVercel, Netlifyあたりも選択肢になりますが、
- 会社でローンチしているサービスがほぼAWSで構築されていること
- それらがTerraformで管理されていること
により、業務に知見を活かせそうなAmplifyを選択しました。
なおSSRについては以下の記事が大変参考になります。
環境
nodeバージョン: 20.11.0
nextバージョン:14.0.4
terraformバージョン:1.7.0
Terraformを実装
まずmain.tfを作ります。
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
"Service" = "myapp"
"Description" = "Managed by Terraform"
"CreatedByRole" = "terraform"
}
}
}
terraform {
required_version = ">= 1.7.0"
backend "s3" {
bucket = "terraform-2024"
key = "myapp/service/production/terraform.tfstate"
region = "ap-northeast-1"
}
}
awsのアカウントIDを自動で取得したいのでdata.tfに記載します。
data "aws_caller_identity" "current" {}
続いてIAMの設定を行います。
resource "aws_iam_role" "myapp" {
name = "myapp"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "amplify.amazonaws.com"
}
}
]
})
}
# ログの書き込み設定が必要そうだったので記載
resource "aws_iam_policy" "myapp" {
name = "myapp"
description = "Policy for myapp"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Sid = "PushLogs",
Effect = "Allow",
Action = [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
Resource = "arn:aws:logs:ap-northeast-1:${data.aws_caller_identity.current.account_id}:log-group:/aws/amplify/*:log-stream:*"
},
{
Sid = "CreateLogGroup",
Effect = "Allow",
Action = [
"logs:CreateLogGroup"
],
Resource = "arn:aws:logs:ap-northeast-1:${data.aws_caller_identity.current.account_id}:log-group:/aws/amplify/*"
},
{
Sid = "DescribeLogGroups",
Effect = "Allow",
Action = [
"logs:DescribeLogGroups"
],
Resource = "arn:aws:logs:ap-northeast-1:${data.aws_caller_identity.current.account_id}:log-group:*"
}
]
})
}
resource "aws_iam_role_policy_attachment" "myapp" {
role = aws_iam_role.myapp.name
policy_arn = aws_iam_policy.myapp.arn
}
メインのAmplifyについて記載していきます。
resource "aws_amplify_app" "myapp" {
name = "myapp"
repository = local.repository_url
# githubのアクセストークンはterraform apply時にターミナル上で入力する
access_token = var.github_access_token
build_spec = <<EOF
version: 1
frontend:
phases:
preBuild:
commands:
- npm ci
build:
commands:
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
EOF
enable_auto_branch_creation = true
enable_branch_auto_build = true
enable_branch_auto_deletion = true
platform = "WEB_COMPUTE"
iam_service_role_arn = aws_iam_role.myapp.arn
auto_branch_creation_config {
enable_pull_request_preview = true
}
environment_variables = {
# APIのURLを設定
NEXT_PUBLIC_API_URL = local.amplify_app_environment_variables.next_public_api_url
# カスタムイメージを設定
_CUSTOM_IMAGE = local.amplify_app_environment_variables.custom_image
}
tags = {
Name = "myapp"
}
}
resource "aws_amplify_branch" "main" {
app_id = aws_amplify_app.myapp.id
branch_name = "main"
framework = "Next.js - SSR"
enable_auto_build = true
stage = "PRODUCTION"
}
# ドメインを設定
resource "aws_amplify_domain_association" "myapp" {
app_id = aws_amplify_app.myapp.id
domain_name = local.domain_name
sub_domain {
branch_name = aws_amplify_branch.main.branch_name
prefix = ""
}
sub_domain {
branch_name = aws_amplify_branch.main.branch_name
prefix = "www"
}
}
locals.tfは以下の通りです。
locals {
repository_url = "https://github.com/yourname/myapp"
}
locals {
amplify_app_environment_variables = {
next_public_api_url = "https://api.myapp.com"
custom_image = "public.ecr.aws/docker/library/node:20.11.0"
}
}
locals {
domain_name = "myapp.com"
}
variables.tfは以下の通りです。
variable "github_access_token" {}
ポイント
1. githubとの接続
githubとの接続にはaccess_tokenが必要になります。
このトークンをソースコード上で管理したくなかったため、variableとして書き出し、terraform plan/applyする際にターミナル上で入力するようにしました。
ただし組織での運用の場合面倒そうなのでより良い方法がありそうです。
ご存知の方コメントいただければ幸いです。
resource "aws_amplify_app" "myapp" {
name = "myapp"
repository = local.repository_url
# githubのアクセストークンはterraform apply時にターミナル上で入力する
access_token = var.github_access_token
...
}
variable "github_access_token" {}
var.github_access_token
Enter a value:
2. カスタムイメージの設定
2024年2月現在、Node.jsのバージョンを指定しない場合16.19.0で構築されるようです。
今回のアプリはnextバージョン:14.0.4につき、Node.jsのバージョンは18.17.0以上が求められます。
従ってDockerイメージを明示する必要があります。
そのためには環境変数_CUSTOM_IMAGE
を用意し、任意のイメージを指定します。
イメージはAWSのECR Public Gallaryから探しました。
今回は20.11.0を選択しました。
resource "aws_amplify_app" "myapp" {
...
environment_variables = {
...
# カスタムイメージを設定
_CUSTOM_IMAGE = local.amplify_app_environment_variables.custom_image
}
...
}
...
locals {
amplify_app_environment_variables = {
...
custom_image = "public.ecr.aws/docker/library/node:20.11.0"
}
}
...
コンソールで確認
ここまでの内容でterraform applyするとAmplifyのリソースが作成されます。
コンソールに入ると「ビルドなし」になっていますが、「ビルド実行」ボタンを押せば開始します。
(Terraform側で何かしら設定すればこの過程は不要?)
ビルド実行ボタンを押して少し待つと、無事デプロイ成功しました🎉
なおドメインの紐付けは多少時間がかかります。
terraform applyした時点で紐付け処理は開始しています。
待っていれば完了し、任意のドメインでアクセスできるようになります。
以上です!
Discussion