タイトルの通りですが、Next.jsのアプリケーションをAWS Amplifyでホスティングする機会があったので試してみました。
また趣味ですがAmplify自体はCDKで実装しています。
目次
やること
今回Next.jsのアプリケーション例として、vercelのサンプルのブログスターターキットを使います。
上記のブログをAmplifyでホスティングします。
またAmplify自体はCDKで構築します。以下ドンピシャなAWS公式の動画があったのでこちらの手順を参考にさせてもらいました。
上記の動画からリンクされている記事(の和訳)である以下も参考になります。
リポジトリ構成
以下のようにアプリとインフラ(CDK)をセットにしたモノレポにしてみます。
. ├── README.md ├── blog # Next.jsのサンプルアプリ └── cdk # AmplifyのCDKプロジェクト
以下実装例です。
事前準備:Next.jsアプリ(ブログ)の作成
yarnでブログスターターキットを取得し、アプリを作成します。
yarn create next-app --example blog-starter .
適当に記事などを作成して、ローカルで起動してみます。
* 記事を作成する場合はblog/_posts/
配下に .md
を作成。
* 画像はblog/public/assets
配下に格納する。記事から画像を参照する場合は、/assets
始まりで記載。
yarn dev
起動したらローカルホストで3000にアクセスします。
記事が見れたので特に問題なさそうです。
※ また以下の記事を参考にシンタックスハイライトの追加のみ実施。
CDK(Amplify)の実装
事前準備
今回はAmplifyのalphaモジュールを使います。
以下のようにalphaモジュールを追加します。
# cdk init cdk init app --language typescript # Amplifyのalpha モジュールを設定 npm i @aws-cdk/aws-amplify-alpha
プロジェクト構成
. ├── README.md ├── bin │ └── cdk_amplify.ts ├── cdk.json ├── cdk.out ├── jest.config.js ├── lib │ └── cdk_amplify-stack.ts # Stackを実装 ├── node_modules ├── package-lock.json ├── package.json ├── parameter.ts # 環境依存パラメータの定義 ├── test │ └── cdk_amplify.test.ts └── tsconfig.json
Stackの実装内容
alphaモジュールのApp
を使用して実装していきます。
以下実装内容の全量です。今回はlib
配下のStackに直接実装しています。
参考資料のAWS公式の動画やブログ記事のサンプルから変えている点を中心に、実装の詳細を説明します。
const amplifyApp = new App(this, "AmplifyAppBlog", { appName: props.appName, // ①GitHubをソースとして使用 sourceCodeProvider: new GitHubSourceCodeProvider({ owner: props.ownerName, repository: props.repositoryName, oauthToken: cdk.SecretValue.secretsManager(props.secretNameForGitHubToken) }), platform: Platform.WEB_COMPUTE, // ②環境変数の設定 environmentVariables: { "AMPLIFY_MONOREPO_APP_ROOT": "blog", "AMPLIFY_DIFF_DEPLOY": "true" }, // ③buildspecの設定 buildSpec: codebuild.BuildSpec.fromObjectToYaml({ version: 1, applications: [ { appRoot: 'blog', frontend: { phases: { preBuild: { commands: ['yarn install --frozen-lockfile'], }, build: { commands: ['yarn run build'], }, }, artifacts: { baseDirectory: '.next', files: ['**/*'], }, cache: { paths: ['node_modules/**/*'], }, } } ] }) }) amplifyApp.addBranch("main", { stage: "PRODUCTION" })
①GitHubをソースとして使用
sourceCodeProvider: new GitHubSourceCodeProvider({ owner: props.ownerName, repository: props.repositoryName, oauthToken: cdk.SecretValue.secretsManager(props.secretNameForGitHubToken) // TokenはSecrets Managerで管理 }),
今回はGitHubをソースコードプロバイダーとして使います。
またGitHubのトークンはSecrets Managerに事前に登録しておき、読み込む形としています。
なおシークレット名はパラメータで設定できるように実装しています。
②環境変数の設定
// ②環境変数の設定 environmentVariables: { "AMPLIFY_MONOREPO_APP_ROOT": "blog", // アプリのルートを指定 "AMPLIFY_DIFF_DEPLOY": "true" // 差分ビルドを有効化 },
今回重要なのはAMPLIFY_MONOREPO_APP_ROOT
です。
Next.jsのアプリが入っているのはソースコードプロジェクトのルートではなく、blog/
配下なので環境変数でパスとして指定します
またAMPLIFY_DIFF_DEPLOY
をtrue
にすることで、フロントエンドの差分ビルドが有効になります。差分がないときはビルドがスキップされます。
③buildspecの設定
buildSpec: codebuild.BuildSpec.fromObjectToYaml({ version: 1, // applicationsでリスト化してAPのルートを指定(モノレポ用の設定) applications: [ { // APのルートを指定(モノレポ用の設定) appRoot: 'blog', frontend: { phases: { preBuild: { // yarnに変更 commands: ['yarn install --frozen-lockfile'], }, build: { // yarnに変更 commands: ['yarn run build'], }, }, artifacts: { baseDirectory: '.next', files: ['**/*'], }, cache: { paths: ['node_modules/**/*'], }, } } ] })
モノレポ用の設定として、applications
で階層化し、appName
でソースコードプロジェクト上アプリを配置しているパスを指定します。この時appName
のパスは②のAMPLIFY_MONOREPO_APP_ROOT
と一致させます。
また、今回Next.jsのアプリ作成時にyarn
を使用しているため、コマンドを全般的に置き換えています。
環境依存パラメータの定義
parameter.ts
に環境依存パラメータを定義するようにしています。今回はBLEAのサンプルの実装方法を参考にしてみました。
import { Environment } from 'aws-cdk-lib'; // Interfaceを定義 export interface AppParameter { env?: Environment, stackName: string, appName: string; ownerName: string; repositoryName: string; secretNameForGitHubToken: string; } // 各環境のパラメータを定義。例はdev export const devParameter: AppParameter = { // 使用する環境のアカウントID、リージョン env: { // account: '', region: 'ap-northeast-1' }, stackName: 'mazyu36-amplify', // Stack名を指定 // ここから下はAmplify Appで使用する値 appName: 'nextjs-blog', // Amplify Appの名称 ownerName: 'mazyu36', // 参照するGitHubリポジトリのユーザー名 repositoryName: 'cdk-amplify', // Next.jsアプリを入れるGitHubリポジトリ名 secretNameForGitHubToken: 'github-token' // GitHubトークンを格納するSecrets Managerのシークレット名 }
上記はbin/cdk_amplify.ts
で使用します。
devParameter
をインポートして、propsとして各パラメータを渡すだけです(これもBLEAの実装方法を参考にしています)
#!/usr/bin/env node import 'source-map-support/register'; import * as cdk from 'aws-cdk-lib'; import { CdkAmplifyStack } from '../lib/cdk_amplify-stack'; import { devParameter } from '../parameter'; // パラメータをimport const app = new cdk.App(); new CdkAmplifyStack(app, 'CdkAmplifyStack', { // 環境はパラメータで指定があればそちらを使用、なければデフォルト env: { account: devParameter.env?.account || process.env.CDK_DEFAULT_ACCOUNT, region: devParameter.env?.region || process.env.CDK_DEFAULT_REGION, }, stackName: devParameter.stackName, // Stack名を指定 // ここから下はAmplify Appで使用する値 appName: devParameter.appName, ownerName: devParameter.ownerName, repositoryName: devParameter.repositoryName, secretNameForGitHubToken: devParameter.secretNameForGitHubToken, });
デプロイの実施
GitHubのトークンを取得
まずはGitHubをソースコードプロバイダーとして使うためのトークンの発行を行います。
手順としては以下になります。
スコープとしては、参考資料に従いadmin:repo_hook
にします。
Secrets Managerにトークンを登録
発行したGitHubのトークンをSecrets Managerに登録します。
「そのほかのシークレットタイプ」にして、トークンを貼り付けます。
その後シークレットの名前を入力します。CDK上で指定するシークレット名と一致させる必要があります。
CDKデプロイの実施
cdk deploy
でAmplifyのアプリを作成します。完了すると以下のようにリソースが作成されます。
Next.jsアプリのデプロイ
私が実施したところ、初回のデプロイは手動でトリガーしないと実施されませんでした。
カスタムリソースなどで頑張ってもいいですが、初回だけのためにそこまで頑張るのも微妙かと思い、上記画面の「ビルドの実行」を押下して対処しました。
ビルドを開始すると以下のようにプロビジョニングから実施されます。
デプロイが完了すると以下のようになります。
動作確認
デプロイ完了後、払い出されたドメインにアクセスします。
アクセスしてNext.jsのアプリが表示されれば問題なしです。これでAmplifyによるホスティングの設定および動作確認完了です。
終わりに
Amplifyでアプリをホスティングするだけであれば、非常に簡単にできます。便利ですね。
Amplify初心者なので、他機能もキャッチアップしてもっと活用していきたいです。