本記事は、CyberAgent Advent Calendar 2022 3日目の記事です。

はじめに

こんにちは。株式会社CAMでバックエンドエンジニアをしている石川です。普段は、 Fensi Platform という CAM のサービス開発基盤のバックエンドを開発しています。

今回は、社内の Cloud Run を使った Next.js ホスティング基盤に Preview Deployment 機能を追加したので、それについて紹介したいと思います。
Next.js ホスティング基盤については、 CAM のテックブログで解説しているので、ぜひそちらを読んでからこちらの記事を読んでいただけると幸いです。

Cloud Run を使った Next.js のホスティング基盤について | 株式会社CAM (cam-inc.co.jp)

Preview Deployment 機能について

Preview Deployment 機能とは、git の開発ブランチやリリースブランチにマージして本番や開発環境にデプロイすることなく、開発者が自分の変更を確認することができる機能です。

Vercel や Netlify などの最近のホスティングサービスでは、 Preview Deployment 機能を提供しているサービスも多くあります。

Preview Deployments – Vercel Docs

Deploy Previews | Netlify Docs

Preview Deployment 機能には下記のようなメリットがあります。

  • ローカルでは確認できないような機能を他の人に影響を与えずに確認できる
  • コードレビュー時に実際に動いているものを見ながらレビューできる
  • 開発中のものをデザイナーやビジネスサイドの人に共有してフィードバックを得られる

従来の Fensi Platform のフロントエンド開発では、コードの変更を開発ブランチなどにマージする前に開発環境で動作確認がしたいような場合、一時的にその人の作業ブランチを開発環境にデプロイして動作確認などをしていました。

そのようなフローだと、想定していなかったバグがあった場合に開発環境を利用している人全員に影響を与えてしまいます。

また、開発環境が1つしかないような場合だと、繁忙期などに開発環境を利用する待ち行列が発生してしまう可能性もあります。

このような課題を解決してエンジニアの開発体験を向上させるため、Next.js ホスティング基盤にGithub の Pull Request ごとに検証環境が簡単に構築できる、Preview  Deployment 機能を用意しました。

Next.js ホスティング基盤

まずは、Next.js ホスティング基盤について簡単に説明したいと思います。

Next.js ホスティング基盤では、静的ファイル置き場に Amazon S3、 CDN に Amazon CloudFront、サーバーのホスティング環境に Google Cloud Run を利用しています。

全体のアーキテクチャは下図のようになっています。

Next.jsホスティング基盤の全体構成

この環境に、 Cloud Run の機能を活用して、全サービスが利用できる Preview Deployment 機能を追加しました。

Preview Deployment 機能のアーキテクチャ

こちらが全体のアーキテクチャ図です。

PreviewDeployment機能の全体構成

以下でそれぞれの要素を詳しく紹介していきます。

Next.js サーバーの Preview Deployment

まずは Next.js サーバー部分の Preview Deployment 機能について解説していきます。

サーバーの検証環境のデプロイでは、 Cloud Run の Revision 機能を利用しています。

Cloud Run の Revision とは、サービスの構成やソースコードを変更してデプロイした際に作成されるバージョンのような概念です。 複数のRevision にトラフィックを分割して流したり、 Revision Tag をつけて Revision 専用の url を発行して、指定した Revision にアクセスできるようにすることができます。

Next.js ホスティング基盤では、Github の Pull Request ごとに  Cloud Run の Revision を作成できるようにしました。

Pull Request ごとに Revision を作成する仕組みはGoogle CloudBuild を利用しており、GitHub の Pull Request にコメントすることでビルドがトリガーされる機能を使って、エンジニアが任意のタイミングで自分の検証用 Revison と Revison Tag を作成できるようになっています。

GitHub からのリポジトリのビルド  |  Cloud Build のドキュメント  |  Google Cloud

pull request からリビジョンを作成する

自分の検証用Revisionへのアクセス

次に、作成された Revision へのアクセス方法について説明します。

下記は、リクエストが Cloud Run へ Routing されるまでの構成図になります。

Next.js のホスティング基盤では、同一GCP上に複数アプリケーションの Cloud Run が動いています。また、Cloud Run は直接外部には公開しておらず、前段に Google Cloud Load Balancing を置いています。LB の設定で各アプリケーションごとに Backend Service を設定していて、 host header をみてマッチする Cloud Runのサービス へトラフィックを流すようになっています。

Google Cloud Load Balancing と Cloud Run の構成図

既存のLBの設定では、各 Cloud Run サービスの最新の Revision にルーティングされるようになっているため、Pull Request ごとに Revision が作成されても、そのRevisionにアクセスすることはできません。

そのため、 Google Cloud Load Balancing に全アプリケーション共通の Preview 用 BackendService と ServerlessNEG を追加しました。

Preview 用の ServerlssNEG では url mask という機能を使って、ルーティングする Cloud Run の Service と Revision を決めるようにしました。 url mask 機能とは、具体的なルーティング先の情報を設定しなくとも、パスやドメイン名をもとに Cloud Run のサービス名と Revision を見つけてルーティングしてくれる機能です。 

例えば、/<service>/<tag> という url mask を設定しておけば、 example.com/foo-service/tag1 とリクエストが来た際は、 foo-service という Cloud Run サービスの tag1 というRevisionにルーティングしてくれます。

今回は、  /<service>/previews/<tag> という url mask の設定と、  previews.example.com のような全アプリケーション共通の preview専用ドメインを設定しました。

これにより、 previews.example.com/foo-service/previews/tag1 のような url にアクセスすることで、自分の開発している Cloud Run のサービスの任意の Revision へアクセスすることができます。

Preview Deployment の Google Cloud Load Balancing と Severless NEG の構成図

Revisonごとの静的ファイルへのアクセス

次に静的ファイルの配信について説明します。

Next.js は SSR をするフレームワークですが、静的ファイルも存在するため、その置き場として Amazon S3 を利用しています。 

S3 バケット内の構造は下記図のように、 Cloud Run の Revision 機能に合わせて、Revisionごとに階層が切られるようになっています。

静的ファイル配信の構成図

こうすることで、 Next.js の Asset Prefix 機能を利用し、静的ファイルアクセス時のパスに、自分の Revision がある階層を指定してアクセスできます。

したがって自分の検証用の Revision でも、問題なく自分の静的ファイルへアクセスできます。

Preview Deployment 時のCDNの設定

最後に CDN の部分について解説します。

CDN には Amazon CloudFront を利用しており、 SSR 結果のキャッシュやカスタムドメインの設定と、Behavior で S3 と Cloud Run へのリクエストの振り分けもしています。

従来のリクエストの振り分けは下図のようになっており、 Default の Behavior は Cloud Run へ行き、 /assets/* という パスパターンが静的ファイルの場所を指しているので S3 へルーティングされます。

Next.jsホスティング基盤のCDNの構成図

今回は、Preview Deployment 機能を追加するにあたり下図のように、各アプリケーションの CloudFrontに Preview 用の Behavior を追加しました。

PreviewDeployment機能のCDNの構成図

Preview用の Behavior では、前のセクションで説明した Google Load Balancing preview 用のドメインを指しています。また、ServerlessNEG url mask Cloud Run のサービス名を特定できるように、CloudFront のオリジンパスで自分の Cloud Run のサービス名を付加するようにしました。

これで、 foo.com というサービスで自分の検証用 Revision にアクセスしたい場合、  foo.com/previews/tag1 というパスでアクセスすれば、 CloudFront は  previews.example.com/foo-service/previews/tag1 という url で Google Cloud Load Balancing へリクエストをproxyしてくれます。

そのあとは上述したように Google Cloud Load Balancing と Serverless NEG が foo-service という Cloud Run サービスの tag1 のRevisionへリクエストをルーティングしてくれます。

まとめ

今回は Amazon CloudFront なども組み合わせて、 Google Cloud Run と Serverless NEG の機能を活用した Next.js の Preview Deployment 機能を紹介しました。

Cloud Run はリクエストが来ない時はコンテナ数をゼロスケールさせられるので、インフラ費用を最小限に抑えながら Preview することができます。

また、 Serverless NEG の url mask 機能を使うことで、サービスごとの Cloud Run 側には設定を追加することなく Preview Deployment 機能が導入できるようになりました。

実際に複数の開発チームで Preview Deployment 機能を活用して、サービス開発をしてくれるようになったのでよかったです!

 

今後もこのようなエンジニアの開発体験が向上できるような機能や仕組みをどんどん作って組織に貢献したいなと思います!