はじめに
前回の記事では、AWS CDKを用いて最小構成のWebサイトを構築しました。
CDKプロジェクトの基本的な流れをひと通り体験し、「なんとなく流れがつかめた」段階です。
本シリーズでは、Next.jsアプリをAWS上で公開するためのインフラ構成を、段階的に構築していきます。
第1回となる本記事では、まず最初のステップとして、ECSが参照するためのコンテナ置き場(ECR)を作り、Dockerイメージをpushするところまで進めます。
本シリーズの構成
1. ECR編(本記事)
2. ECS Task Definition編
3. ALB編
4. ECS Service編
5. セキュリティ編
全体のゴール
Next.jsアプリをAWS上で公開するために、以下の構成を作ります。
- ECR:コンテナイメージ置き場
- ECS(Fargate):コンテナ実行基盤
- ALB:外部公開用の入口
- CloudWatch Logs:ログ確認
全体の手順
Next.jsアプリをAWS上で公開するための全体の流れは、以下の通りです。
1. ECR(コンテナ置き場)を作成し、Dockerイメージをpushする
2. ECS Task Definitionを作成する
3. ALB + TargetGroup + HealthCheckを構築する
4. ECS Serviceを作成して常時稼働させる
5. セキュリティグループを調整し、疎通を確認する
本記事では、このうち 1. ECRの作成とイメージのpush までを扱います。
1-1. 検証用の最小Next.jsアプリを作成する
本記事では、ECRへpushするコンテナイメージとして、
検証用の最小構成のNext.jsアプリを作成します。
1-1-1. Next.jsアプリを新規作成する
以下のコマンドで、Next.jsアプリを新規作成します。
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
実行すると設定選択の質問が表示されます。
ここではおすすめの設定(recommended defaults)を使用して問題ありません。
❯ Yes, use recommended defaults
この選択により、TypeScriptとESLintが有効になり、
App Routerを使用した構成でプロジェクトが作成されます。
本記事ではNext.js13以降(App Router)前提で進めます。
1-1-2. 検証用の最小ページを作成する
生成されたapp/page.tsxを、以下のように修正します。
export default function Home() {
return (
<main style={{ padding: '40px' }}>
<h1>My Next.js App</h1>
<p>これはインフラ検証用のサンプルアプリケーションです。</p>
</main>
);
}
ローカルで一度起動し、表示を確認します。
npm run dev
ブラウザで
http://localhost:3000
にアクセスし、画面が表示されればOKです。
1-1-3. Dockerfileを作成する
Next.jsアプリをコンテナとして起動するため、
プロジェクト直下にDockerfileを作成します。
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
ポイントは以下です。
-
npm run build:本番用ビルドを実行 -
npm start:next startによる本番起動 - ポート番号は3000(後続のECS / ALB設定で使用)
1-2. CDKプロジェクトの用意
新規作成する場合
以下のコマンドを実行して、CDKプロジェクトを作成します。
mkdir cdk-nextjs-infra
cd cdk-nextjs-infra
cdk init app --language typescript
既存プロジェクトを利用する場合
すでに CDKプロジェクトが存在する場合は、それを利用しても問題ありません。
(TypeScriptのCDKプロジェクトであれば、そのまま利用できます)
ディレクトリ名は任意で問題ありません。
本シリーズでは、インフラ用CDKプロジェクトとして
cdk-nextjs-infraというディレクトリ名を使用する前提で説明します。
1-3. CDKでECRリポジトリを作成する
CDKプロジェクト内に"lib/ecr-stack.ts"を作成します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecr from 'aws-cdk-lib/aws-ecr';
export class EcrStack extends cdk.Stack {
public readonly repository: ecr.Repository;
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.repository = new ecr.Repository(this, 'Repository', {
repositoryName: 'my-nextjs-app',
removalPolicy: cdk.RemovalPolicy.DESTROY, // スタック削除時にリポジトリも削除する(検証用)
emptyOnDelete: true, // リポジトリ削除時に中のイメージも自動で削除する(検証用)
imageScanOnPush: true,
});
new cdk.CfnOutput(this, 'RepositoryUri', {
value: this.repository.repositoryUri,
});
}
}
なぜ最初にECRなのか
ECSのTask Definitionでは「どのコンテナイメージを起動するか」を指定します。
ECRにイメージが存在しないとECS側が始まらないため、最初にECRを作ります。
1-4. Stackをbin側で呼び出す
CDKプロジェクトのbin配下のtsファイル(cdk-nextjs-infra.ts)を以下のように書き換えます。
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { EcrStack } from '../lib/ecr-stack';
const app = new cdk.App();
const env = {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
};
new EcrStack(app, 'NextjsInfraEcrStack', { env });
cdk init 実行時に自動生成される
lib/cdk-nextjs-infra-stack.ts(デフォルトスタック)は、本シリーズでは使用しません。
本シリーズでは、用途ごとに作成するスタックのみを利用するため、
自動生成されたデフォルトスタックは削除して構いません。
1-5. deploy(ECR作成)
cdk deploy NextjsInfraEcrStack --profile <プロファイル名>
デプロイが成功すると、Outputs に RepositoryUri が出ます。
例:
Outputs:
NextjsInfraEcrStack.RepositoryUri
= <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/my-nextjs-app
本記事で作成したスタックに含まれるAWSリソースは、削除するまで料金が発生します。
検証が不要になった場合は、以下のコマンドでスタックを削除してください。
cdk destroy NextjsInfraEcrStack --profile <プロファイル名>
1-6. Next.jsのDockerイメージをbuild
Next.jsプロジェクト側でdocker buildを実行します。
docker build -t my-nextjs-app:latest .
ビルドが成功すると、最後に
naming to docker.io/library/my-nextjs-app:latest
と表示されます。
1-7. ECRへログイン → tag → push
ECRへログインしてpushします。
1-7-1. ECRへログイン
aws ecr get-login-password --region ap-northeast-1 --profile <プロファイル名> | docker login --username AWS --password-stdin <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com
<account-id> には、AWSアカウントID(12桁)を指定します。
ログインに成功すると、
Login Succeeded
と表示されます。
本記事ではリージョンを ap-northeast-1(東京リージョン)前提で説明しています。
他リージョンを利用する場合は、リージョン指定部分を読み替えてください。
1-7-2. Dockerイメージにタグ付け
docker tag my-nextjs-app:latest <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/my-nextjs-app:latest
docker tag ① ②
①ローカルに存在するDockerイメージの名前+タグ
②ECRリポジトリのリポジトリURI+リポジトリ名+タグ
1-7-3. ECRへイメージをpush
docker push <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/my-nextjs-app:latest
pushが成功するとdigestが表示されます。
例:
latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 2619
1-8. pushできたか確認
aws ecr describe-images --repository-name my-nextjs-app --region ap-northeast-1 --profile <プロファイル名>
以下のように表示されれば成功です。
"imageStatus": "ACTIVE"
AWSコンソールで確認する
AWSコンソールからも確認しておきます。
- AWSコンソール → ECR → リポジトリ
-
my-nextjs-appリポジトリをクリック - 「イメージ」タブを開く
latestタグの付いたイメージが表示されていれば、
Dockerイメージのpushは正常に完了しています。
これで、AWS上に本番用コンテナイメージが置かれていることを確認できました。
ここまでの成果
成果
- CDKでECRリポジトリを作成できた
- Next.jsのDockerイメージをbuildできた
- ECRへpushして、AWS上にコンテナイメージが置けた
「インフラ側」と「アプリ側」が、初めてつながった瞬間です。
次回
次はECS側の設定に進みます。
- Task Definition(port / env / logs)
- ALB + TargetGroup + HealthCheck
- ECS Service(desiredCount=1)
いよいよ「実際にAWS上で動く」フェーズに入ります。