NextJSのWebアプリをAmplify Gen2デプロイしてみた

2024.04.02

昨年発表されたAmplify Gen2(プレビュー)ですが、日々機能が少しづつ追加されており、完成度が高まってきました。 前回の記事で作成したNextJS Server ComponentsのWebアプリケーションをHostingし、デプロイまで進めてみました。

Ampify Gen2のHostingの概要

従来のAmplifyでWebアプリケーションをHostingする場合、S3を使ったstatic website hostingと、Amplify Hostingの2つがありましたが、Amplify Gen2では「Amplify Publish」のようなコマンドが無くなり、基本の選択肢からS3ホスティングが外れました。

Amplify Gen2はCustom Resourceという、AmplifyのCDKアプリケーションに既存のCDKコンストラクトを追加する機能があるので、お手軽にAmplify Gen2+S3でHostingしたい時は、NextJSのリソースをStatic Exportし、既存のAmplifyスタックからcreateStackして、Hosting用のCDKを追加すると、Amplifyのデプロイ時に一緒にCDKを実行し、デプロイします。

話が逸れつつありますが、概ねこのようなカスタムリソースで動作します。

amplify/data/backend.ts

import { defineBackend } from "@aws-amplify/backend";
import { auth } from "./auth/resource";
import { data } from "./data/resource";

import * as aws_s3 from "aws-cdk-lib/aws-s3";
import {
  Distribution,
  OriginAccessIdentity,
} from "aws-cdk-lib/aws-cloudfront";
import { RemovalPolicy } from "aws-cdk-lib";
import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
import { S3Origin } from "aws-cdk-lib/aws-cloudfront-origins";
import { Effect, PolicyStatement, ServicePrincipal } from "aws-cdk-lib/aws-iam";

const backend = defineBackend({
  auth,
  data,
});

const contextJson = JSON.parse(process.env.CDK_CONTEXT_JSON ?? "{}");
const stackprefix =
  contextJson["amplify-backend-type"] === "sandbox"
    ? contextJson["amplify-backend-name"]
    : "";
const subStack = backend.createStack(stackprefix + "SubStack");

// Create an S3 bucket for the website
const destinationBucket = new aws_s3.Bucket(subStack, "WebsiteBucket", {
  bucketName: `cdk-hogetest-content-bucket`,
  blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL,
  autoDeleteObjects: true,
  removalPolicy: RemovalPolicy.DESTROY,
});

const originAccessIndetity = new OriginAccessIdentity(subStack, "OAI");
destinationBucket.grantRead(originAccessIndetity);

// Create a CloudFront distribution
const distribution = new Distribution(subStack, "distro", {
  defaultBehavior: {
    origin: new S3Origin(destinationBucket, {
      originAccessIdentity: originAccessIndetity,
    }),
  },
  defaultRootObject: "index.html",
});

// Deploy the contents of the 'website' directory to the S3 bucket
new BucketDeployment(subStack, "DeployWebsite", {
  sources: [Source.asset("./out")],
  destinationBucket,
  distribution,
});

// S3 - BucketPolicy
const destinationBucketPolicyStatement = new PolicyStatement({
  actions: ["s3:GetObject"],
  effect: Effect.ALLOW,
  principals: [new ServicePrincipal("cloudfront.amazonaws.com")],
  resources: [`${destinationBucket.bucketArn}/*`],
});
destinationBucket.addToResourcePolicy(destinationBucketPolicyStatement);

next.config.mjs

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

tsconfig.json

...
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules/*", "amplify/*", "amplify-backup/*"]. //amplifyフォルダを除外
}

とはいえ、今回はNextJSのServer Componentsを使いたいので、Amplify Hostingを選ぶことになります。

Amplify HostingのドキュメントはAmplify Gen2内には存在しないのですが Ampligy Gen2用のUIが用意されています。プレビュー版で、幾つか開発中の機能はあるものの、大幅に使いやすくなっていると感じました。

今回はGithubと連携し、Pushに合わせてリソースをデプロイするオーソドックスなデプロイを構築します。

デプロイ

Amplifyのホスティングのページに進むと、Amplify Gen2のSuggestが表示されています。

今回は、既にNextJSのソースコードがGitHubに配置されているものとします。

githubと連携し、リポジトリとブランチを指定します。

リポジトリをスキャンし、フレームワークが自動選択されることが分かります。

詳細設定からビルドイメージを選択できます。 執筆時点では、デフォルトの設定のままデプロイまで行うことが出来ており、特に設定を変えていません。

Gyazo

最後まで進めると、デプロイが完了しました。初回は10分ほど掛かりました。 ビルド・デプロイの項目をクリックすると、それぞれのプロセスの標準出力を確認し、異常がなかったかどうかを確認できます。

ここは従来のAmplify Hostingと同様、amplify.ymlで設定されたものが反映されます。 過去のデプロイの履歴の確認や、再デプロイも可能です。切り戻しに便利ですね。

Amplify Gen2のUIメニュー

これも従来のAmplify Hostingと同様ですが、環境変数やSecretを設定でき、ブランチ毎に値を出し分ける事ができます。 環境変数は、Amplify Hostingで管理し、CDK・フロントエンドで使用することができます。 Secretは、SSM Parameter Storeで管理し、Amplifyで作成したBackendサービスに適用できます。 記事には含めていませんが、Function(Lambda)を作成して、環境変数としてセキュアな値を受け取りたい時に便利でした。

リポジトリの設定は、ブランチの管理がポイントで、ブランチ名で判断し、GitHub上でのアクションが発生した時、自動でビルド処理を走らせるかどうかの調整ができます。

ビルドの設定では、amplify.ymlを編集し、ビルドとデプロイの設定を変更することができます。 また、ビルド時の通知や、incoming WebHookを飛ばし、例えばCodeCatalyst等の他アプリケーションと連携するような設定を行います。

カスタムドメインはまだ使えない

本来は、このメニューから、Route53や、独自に取得したドメインを簡単に設定できるのですが まだ利用できませんでした。ご注意下さい(見落としていて、痛い目を見ました・・・)

おまけ:デプロイ環境のローカルテスト

デプロイした環境をローカルで動作チェックしたい時、デプロイした環境とsandboxで作成した環境は別になります。 この環境を識別するファイルが、Amplify V6から用意された、amplifyconfiguration.jsonです(以前のaws-exports)。

generate configコマンドで、デプロイされたamplifyのスタックを選択することで、指定した環境のamplifyconfiguration.jsonを生成できるようになりました。以前の、Amplify env checkoutと似たような動きとして使えそうです。デプロイ時も、内部でこのコマンドが実行されているようです。

npx amplify generate config --stack hogehoge

ただ、執筆時点では、変更したCognitoのパスワードポリシーがconfigに反映されないといった不具合も確認されており プレビュー中ということもあり、正式版の発表が待たれる所ではあります。

その他、CLIを使用したリファレンスはこちらでまとめられています。

まとめ

Amplifyの基本的なアプリ作成とデプロイまでを紹介しました。 まだまだプレビュー版のAmplify Gen2ですが、ツールファーストからコードファーストに切り替わり、これまでのAmplifyの知識からのアップデートが必要と感じました。