SODA Engineering Blog
🌳

[Frontend Replace] インフラ設計篇

に公開

こんにちは。FE チームの MiyukiP です。

これまでFrontendリプレイスプロジェクトのエコシステムアーキテクチャについてお伝えしました。
本稿では、それらを配信するインフラや開発環境について紹介していきます。

前提

元々、スニーカーダンクはFrontend/API一体のモノリスをECSの単一serviceにデプロイして、ユーザーに配信していました。
今回のリプレイスにあたって、従来のserver serviceの他に、新たにfrontend serviceを作成して、そのservice内の前段にNginxをリバースプロキシとして設置して、段階的なページごとのリプレイスを実現しています。

インフラ構成

まずはFrontendリプレイスプロジェクトのインフラ構成図を紹介します。

インフラ構成図

各リソースの役割は以下のようになります。

  • CloudFront: 静的アセットをキャッシュして、Edgeから配信する
  • ALB: APIをserver serviceに、それ以外のページをfrontend serviceにルーティングする
  • S3: ユーザがアップロードした画像を格納
  • ECS
    • frontend service
      • Nginx: リバースプロキシとしてルーティング。アクセスログの取得
      • Next.js: リプレイスされたページのリクエストにレスポンスする。静的アセット配信のOriginとして利用
    • server service
      • API通信やそれ以外のページを配信

デプロイツール

ECSのデプロイには、kayac/ecspressoを利用しています。
ecspressoをGitHub Actionsから呼び出すことで、デプロイを自動化しています。
また、ビルドやデプロイに関して、モノリスと共通のワークフローになるものがあったので、それらはReusing workflowsとして共通化しました。

移行戦略

モノリスのECSから、Next.jsのECSに移行していく上で、以下のような戦略を取りました。

  • ルーティング
    • 移行済みページへの移行は、リバースプロキシでパスベースでルーティングさせることで実現させました
    • ALBの加重ターゲットグループによって、最初はserver serviceのみルーティングだったものを、徐々に重み付けしていって、段階的にfrontend serviceに移行していきました

Nginxの設定例

# 移行済みpath
location ~* ^/{移行済みpath} {
    client_max_body_size 8m;
    client_body_buffer_size 16k;
    client_body_temp_path /dev/shm/nginx_client_body_temp;

    proxy_buffering on;
    proxy_buffer_size 8k;
    proxy_buffers 64 8k;
    proxy_max_temp_file_size 1024k;
    proxy_temp_path /dev/shm/nginx_proxy_temp;

    proxy_set_header Host ${HOST};
    proxy_set_header X-Real-IP ${REMOTE_ADDR};
    proxy_set_header X-Forwarded-For ${PROXY_ADD_X_FORWARDED_FOR};
    proxy_set_header X-Forwarded-Proto ${SCHEME};

    proxy_pass ${FRONTEND_URL};
}

開発環境

ここからは開発環境まわりについて、お伝えしていきます。

Storybookのデプロイ

開発中のStorybook

社内IPアドレス限定でStorybookをS3にデプロイしました。
デプロイはGitHub Actionsのワークフローとして登録しているので、誰でも気軽にGitHubから更新することが可能です。
こうすることで、エンジニアやデザイナーがUIカタログを簡易に確認することができるようになりました。

GitHub Actionsの設定例

jobs:
  deploy-storybook:
    name: Deploy Storybook to S3
    runs-on: ubuntu-24.04
    timeout-minutes: 10
    steps:
      - name: Checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install

      - name: Build Storybook
        run: bun run build-storybook

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4.0.1
        with:
          # AssumeRoleの設定など

      - name: Deploy Storybook to S3
        run: |
          aws s3 sync ./storybook-static s3://${S3_BUCKET_NAME}/${S3_BUCKET_PATH} --acl public-read --delete

local環境開発

dev/prod環境はDockerでコンテナ化して、ECSにデプロイしているのですが、local環境では next dev で開発するようにしています。そうすることでホットリロードの恩恵を受けることができ、開発体験が向上するからです。
加えて、local環境からはdev環境のAPIを叩くことができるようにしています。
これはlocalのAPIを叩く設定だと、モノリス側のdocker composeも必要になるので、開発者体験を損なうからです。

以下の設定を next.config.ts に追加することで、local環境からdev環境のAPIを叩くことができます。

next.config.ts
  async rewrites() {
    return [
      {
        source: "/api/:path*",
        destination: "https://{DEV_HOST}/api/:path*",
      },
    ];
  },

NODE_ENV と闘った話

公式ドキュメントにもあるように、Next.jsでのNODE_ENVnext dev 利用時は development 、他は production になります。
ですので、Dockerで next start を利用した場合には、どの環境であれ、NODE_ENVproduction になります。
そうすると、Datadogで監視する時に、envで環境を絞り込もうとした際に困ります。

これを回避するために、ビルド時に NEXT_PUBLIC_ENV を設定するようにしました。
環境変数はGitHub Actionsのワークフローで設定しています。

docker build --build-arg NEXT_PUBLIC_ENV=${ENV} -t ${IMAGE_NAME} .

これでクライアント側のエラーログにおいても、環境で絞り込むことが可能になりました。

まとめ

本稿では、Frontendリプレイスプロジェクトのインフラ周辺についてお伝えしました。
これにて、モノリス(Vue.js)からNext.jsへのリプレイスプロジェクト関連の記事は一区切りつきました。

弊社のFrontendリプレイスプロジェクトはまだまだ始まったばかりですが、質問やフィードバックがありましたら、コメントでお気軽にどうぞ。
みなさんのフロントエンド移行に何か有益な情報が提供できていれば幸いです!


関連記事

参考リンク

SODA Engineering Blog
SODA Engineering Blog

Discussion