Next.js製の自作ブログをAppRunnerにデプロイ

公開日: 

はじめに

2022 年 9 月 24 日現在、このブログのホスティングは Vercel に任せているんですが、Vercel は無料利用の範囲が定められています。今回は、広告を貼りたい場合や、その他無料利用の枠をはみ出したい欲望に駆られた時のために、AWS を使ってデプロイする練習をしてみました。

具体的には、AWS のAppRunnerというサービスを利用しています。AppRunner は、ソースコードの変更を検知して、自動的にデプロイする方法も選択できるらしいですが、今回は GitHubActionsDocker の勉強も兼ねたかったので、ECR を用いてデプロイしています。

デプロイのイメージは上の図の通りです。

ECR には無料枠はあるのですが、その枠を超えるとストレージの容量によって課金されていきます。

ECR の料金

https://aws.amazon.com/jp/ecr/pricing/

なので、push するイメージの容量は小さいに越したことはありません。そこで今回は Next.js の standaone モードというのを利用します。

Next.js の standalone モード

https://nextjs.org/docs/advanced-features/output-file-tracing#automatically-copying-traced-files

https://zenn.dev/team_zenn/articles/nextjs-standalone-mode-cloudrun

要約すると、Next.js で standalone モードというのを有効にすることで、ビルド時に node_modules の中から必要なファイルのみをコピーし、.next/standalone 以下に自動で保存してくれるため、.next/standalone のみでアプリを動作させることができ、その結果ビルド後のサイズを大幅に削減することができる。というものらしいです。

せっかくなので、使います。

デプロイしてみる

docker イメージを作る

まずは ECR に push するためのイメージを作るために Dockerfile を書いていきます。

Dockerfile

dockerfile
# Install dependencies only when needed
FROM node:16-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn --frozen-lockfile

# Rebuild the source code only when needed
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build

# Production image, copy all the files and run next
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
CMD ["node", "server.js"]

https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile

公式の exampleを参考にしながら、上のような Dockerfile を作ります。

  1. 依存関係の取得
  2. ビルド
  3. サーバーの起動

の 3 つのステージに分けてマルチステージビルドを用いて 1 つの Dockerfile でまとめました

公式ドキュメントの他には下のブログを参考にしています。

https://zenn.dev/team_zenn/articles/nextjs-standalone-mode-cloudrun

手元で動作確認

ローカル環境でイメージを作成し、そのイメージを動作確認します。

docker build -t test .

test という名前でイメージを作成!

docker run -p 3000:3000 test

3000 番ポートでアプリを起動!

localhost:3000 でブラウザからアクセスできる!

ECR のリポジトリの作成

イメージを push するために、ECR のリポジトリを作成していきます。

AWS のコンソールから『Elastic Container Registory』を選択します。

  • パブリックを選択
  • リポジトリ名を入力(今回は『blog』という名前にした)

下の画像のようにリポジトリが作成されていれば大丈夫です。

ここで作成した blog というレポジトリの中に自動的にイメージが保存されていきます。

IAM ユーザーの作成

続いて、GitHubActions から ECR にイメージを push するための IAM ユーザーを作成します。

AWS のコンソールから『IAM』を選択して、ユーザーの追加を押します。

  • 適当にユーザー名を入力
  • 『アクセスキー - プログラムによるアクセス』を選択
  • 『既存のポリシーを直接アタッチ』を選択
    • AmazonEC2ContainerRegistryPowerUserを選択

以上を設定して、IAM ユーザーを作成します。ユーザーのリストに作成したユーザーが表示されていれば大丈夫です。

GitHubActions で使う、docker/login-action@v2のドキュメントに、『ECR に push するために、AmazonEC2ContainerRegistryPowerUser の権限がある IAM ユーザーを使え』と書いてあります。

https://github.com/marketplace/actions/docker-login

GitHubActions を使って ECR に push

参考: GitHubActions のドキュメント

https://docs.github.com/ja/actions

続きまして、GitHubActions による workflow を作成していきます。

内容としては

  • job の発火タイミング: master ブランチへの push
  • job の内容: docker イメージを作成して、ECR に push

これだけ。

これを /.github/workflows ディレクトリ下に yaml ファイルとして記述していきます。

push.yml
name: image-push-to-ECR
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Login to ecr
        uses: docker/login-action@v2
        with:
          registry: ${{ secrets.ECR_ENDPOINT }}

      - name: Build and push
        id: docker-build
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: ${{ secrets.ECR_ENDPOINT }}/${{ secrets.ECR_REPOSITORY }}:latest
          cache-from: ${{ secrets.ECR_ENDPOINT }}/${{ secrets.ECR_REPOSITORY }}
  • configure-aws-credentials
    • AWS の認証情報を GitHubActions で便利に扱えるイメージ
  • docker-login
    • docker レジストリへのログインを GitHubActions でするためのイメージ
  • buile-push-action
    • docker イメージの push を GitHubActions でするためのイメージ

上記の 3 つの便利なイメージが公式から出ていたのでそれらのドキュメントを参考にしながら、ECR への push を実現しています

AppRunner でデプロイ

最後に、AppRunner でデプロイしていきましょう。

AWS のコンソールから『AWS App Runner』を選択します。

『サービスの作成』を選択

  • 『コンテナレジストリ』を選択
  • 『Amazon ECR』を選択
  • コンテナイメージの URI を入力
    • URI は ECR から確認できます。
    • タグをつけるのも忘れずに
  • 『自動』を選択
  • 『新しいサービスロールの作成』を選択
    • 『AppRunnerECRAccessRole』と入力
    • 過去に作成したことがある人は、『既存のサービスロールを選択』から選択できます
  • サービス名を適当に入力
  • ポート番号を 3000 番に変更

ここまで設定できたら、サービスを作成します。

しばらくして、上の画像のようにステータスが『Running』になったら、指定された URL でブラウザからアクセスできるはず!!!

大成功!

最後に

以上が、Next.js のアプリケーションを AppRunner でデプロイする流れでした。

使った AWS のサービスは

  • Elastic Container Registory
  • App Runner

のみでそこまで複雑なことはしてないので、何か変な部分ではまらない限りは短時間でできるのではないでしょうか。ちなみに自分は、Docker イメージを作成する部分でハマりまくって、動作するイメージを作成するまで 2 日間かかりました

こんなことをしておいてあれですが、ブログのホスティングにはできるだけお金をかけたくないので、一旦は Vercel のホスティングで運用しようかなと思ってます

では

Bye