マンガ投稿チームでWebアプリケーションエンジニアをしているid:stefafafanです。この記事では、最近私がチーム向けに整備したDeployment Preview環境の事例を紹介します。
Pull Requestベースの開発をする際の「Pull Request専用の確認環境」のことを、私のチームでは「Deployment Preview」と呼んでいます。
Netlify、Cloudflare Pages、Vercelをはじめとして、さまざまなサービスがこの機能を提供しています。それぞれ「Deploy Previews」や「Preview Deployments」など表記はいろいろとありそうです。
Deployment Previewを実現するには、Vercelのような既存のサービスを活用するか、クラウドサービスを活用して自分たちで組み立てるかということになります。
ここで私のチームで開発している「マンガノ」の技術スタックは以下の通りですが、この構成のサービスが問題なく動く確認環境であることが必須要件になります。
またチームのエンジニアとしては、
という気持ちもありました。その上で、
という要件もありました。
これらの要件を踏まえた結果、今回はGoogle Cloudを活用した構成を考えることに決めました。*1
さっそく完成した構成図を紹介します。
もともとNext.js側にもGraphQL側にもDockerfileがあるので、個別にCloud Runにデプロイする形で構成しています。またGoogle認証をかけるため、Cloud Load BalancingにIdentity-Aware Proxyを適用させています。
これでPull Requestを開くと、ブランチ名に対応する確認環境が次のようなURLで見られるようになっています。
https://branch-name.frontend.example.com
それでは、この構成を実現するのに必要だった主な作業を紹介します。
コンテナ化されている場合は難しいことはあまりなくて、公式ドキュメントを参考に練習して雰囲気を理解しました。
Deploying to Cloud Run using Cloud Build | Cloud Build Documentation | Google Cloud
判断ポイントは1つあって、それは「Cloud Buildを使う」か「GitHub Actionsでやる」かです。Google Cloudではリポジトリにcloudbuild.yaml
ファイルを用意し、そこにbuild・push・deployのステップを記述するという方法が上記のドキュメントでも紹介されていますが*2、同様のことはGitHub ActionsのWorkflow内のStepでもできます。
私のチームのエンジニアはGitHub Actionsの方が書き慣れている上、最近はWorkload Identity Federation*3も活用できるようだったので、こちらを選びました。
Googleは公式でGitHub Actionsをいくつか提供しており、最終的に以下の3つを活用しました。
Google Cloudとの認証とgcloudコマンドの準備は、以下のようなコードをちょっと書くだけで終わりです。以後のStepでは、gcloudがそのまま使えます。
jobs:deploy:runs-on: ubuntu-latestpermissions:contents:"read"id-token:"write"steps:-name: Checkoutuses:"actions/checkout@v3"-name: Authenticate Google Clouduses:"google-github-actions/auth@v0"with:workload_identity_provider:"..."service_account:"..."-name: Setup Cloud SDKuses:"google-github-actions/setup-gcloud@v0"
イメージのビルドとデプロイはこのように記述します。
env:REPOSITORY: my-repositoryPROJECT: my-deploy-previewLOCATION: asia-northeast1SERVICE: my-serviceCLOUD_SQL_INSTANCE: my-sql-instance...steps: ...-name: Configure dockerrun: gcloud auth configure-docker ${{ env.LOCATION }}-docker.pkg.dev-name: Build imagerun: | docker build -t ${{ env.LOCATION }}-docker.pkg.dev/${{ env.PROJECT }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }} -f ./Dockerfile . # gcloud auth configure-docker の後であればArtifact Registryへ docker push することができる-name: Publish image to Google Artifact Registryrun: | docker push ${{ env.LOCATION }}-docker.pkg.dev/${{ env.PROJECT }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}-name: Deploy to Cloud Runuses: google-github-actions/deploy-cloudrun@v0with:service: ${{ env.SERVICE }}image: ${{ env.LOCATION }}-docker.pkg.dev/${{ env.PROJECT }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}region: ${{ env.LOCATION }} # 別のStepで抽出したgit branch名をrevision tagとして指定するtag: ${{ steps.extract_branch.outputs.branch }} # 他のflagがあれば個別に指定できる。ここでCloud SQLとの接続とかも指定するflags: --add-cloudsql-instances=${{ env.PROJECT }}:${{ env.LOCATION }}:${{ env.CLOUD_SQL_INSTANCE }} # 環境変数が指定できるenv_vars: | ... # Google Secrets Managerの値も指定できるので安心secrets: | MYSQL_USER=MYSQL_USER:latest MYSQL_PASSWORD=MYSQL_PASSWORD:latest ...
全体的にシンプルに書ける上に、デプロイ時の環境変数やSecrets Managerの値も簡単に指定できてとても便利です。マンガノではGraphQLが動いているイメージとNext.jsが動いているイメージをデプロイしたいので、それぞれのイメージに対して上記の記述を書いています。
以上でCloud Run上でアプリケーションは動かせますが、Google認証をかけるには追加でコンポーネントをいくつか用意する必要があります。最終的に、ロードバランサー周りのより詳細なコンポーネントの図はこうなります。
今回の要件を実現するには以下の3点が必要になります。
Identity-Aware ProxyをかけるにはSSL化されている必要があるので、証明書を取得しないといけません。また、マンガノのDeployment Previewはブランチ名をサブドメインに登録する形(branch-a.frontend.example.com
みたいなイメージ)を想定しているので、*.frontend.example.com
のワイルドカード証明書を取得できると要件にマッチします。
2022年6月現在、Google CloudのCloud Load BalancingのWeb UI経由で証明書をセットしようにもワイルドカード証明書は作れません。代わりに最近発表されたCertificate Managerというサービスを使うと実現できるので今回はこちらを利用しました。*5
具体的な用意の仕方はクラスメソッドさんのこちらの記事によくまとまっています。
ここでサブドメインbranch-a.service-a.example.com
が、Cloud Runの特定サービスの特定リビジョンタグに向くようにする必要があります。つまり、Cloud Runにあるservice-a
サービスのbranch-a
リビジョンタグに向いてほしいということです。
Google Cloudでこういう振り分けをしてくれる機能にはLoad BalancerのURL Mapと、Serverless Network Endpoint Group(NEG)のURL Maskがあります。
URL Mapはホストやパスを元に指定したCloud RunサービスやCloud Storageバケットに振り分ける機能ですが、単体ではCloud Runのリビジョンタグに向けられません。例えばdevelop・staging・productionの3環境があり、対応する3つのCloud Runサービスに振り分けるのならURL Mapで十分ですが、今回はブランチごとに環境がほしいのでCloud Runサービスをあらかじめ大量に立てておくなどが必要になり少し面倒です。
URL maps overview | Load Balancing | Google Cloud
一方、Serverless NEGのURL Maskは今回のユースケースに合致している機能で、バックエンドのサービスごとに利用できるプレイスホルダーがいくつかあり、Cloud Runに向ける場合は<service>
と<tag>
が使えます。
なので今回のケースでは<tag>.<service>.example.com
を設定したServerless NEGを1つ用意するだけで、branch-a.service-a.example.com
のアクセスをCloud Runのservice-a
サービスのbranch-a
リビジョンタグに向けることが実現できます。
ここまでできればIdentity-Aware Proxyの設定はあまり難しいところはなく、ドキュメントに沿って準備すると完成します。
gcloud run deploy | Google Cloud CLI Documentation
一点あるとしたら、ロードバランサー経由でサービスを閲覧できるようにするには、Cloud Run側のIngressやAuthenticationの設定をいじる必要があるということです。
IAPを有効化したあと、Ingress側を「Allow internal traffic and traffic from Cloud Load Balancing
」に、そして Authentication を「Allow unauthenticated invocations
」にすると、IAP側の認証に任せてサービスを公開できます。Ingressの設定により、ロードバランサーを通さずCloud RunのURLに直接アクセスしても見れないという状態になります。
このIngressやAuthenticationの設定は、GitHub Actions経由でCloud Runにデプロイする際にオプションとして指定ができます。--ingress=internal-and-cloud-load-balancing
と--allow-unauthenticated
のオプションですね。詳しくはgcloud run deploy
のドキュメントを参照してください。
gcloud run deploy | Google Cloud CLI Documentation
認証のかかったDeployment Previewとして必要最低限の整備はここまでで完成です。
上記以外にも個人ブログに少し書いた話題が2つあるので、ここで軽く紹介します。
まず上記の要件として説明したように、マンガノのアプリケーションはユーザ認証にFirebase Authenticationを利用していますが、今回のようにドメインがブランチごとに変わるDeployment Previewに関しては動かない部分があったためGitHub Actionsで対応しました、という話を次の記事に書いています。
これはGoogle Cloudに限った話ではないので、Deployment Previewのような仕組みを用意したのにFirebase Authenticationの承認済みドメインの扱いで困っている方は参考にしてもらえたら嬉しいです。
もう1つの記事は、Infrastructure as Codeになっていない部分をTerraformに落とし込みましたという話です。実はgcloudにTerraform向けにエクスポートするための便利な機能が備わっているため、その紹介をしています。
完成した環境を見直して、よかったと思える点をまとめます。
main
ブランチの様子も自然とこの環境で確認できる一方、ひとまず利用できる状態になったところでこの記事を書いているので、これから調整したい点もまとめておきます。
Cloud Storageにあるようなライフサイクルの機能はないため、GitHub Actionsなどで定期的に古いイメージを消したりしようかと考えています。幸いgcloudのコマンドで一定期間古いイメージをフィルターして一覧できそうなので、簡単なコマンドで対応できそうです。
全ブランチでGitHub Actions経由のデプロイが行われるようになった結果、デプロイ時間を改善したいという気持ちがエンジニアメンバー間で強まったので、対応していきたいです。エンジニアが毎日目にしているGitHub Actions側でビルドもデプロイもしていることによってこのあたりがより可視化されたので、この点よかったと思っています。
最初に紹介したように私はSREではなく、普段はGoやTypeScriptなどアプリケーションコードを書く仕事がメインですが、今回Google Cloudに入門して大きくハマることなくDeployment Previewの仕組みをチーム向けに用意することができました。
構成図も理解しやすいシンプルな構成になったので、今後メンテナンスするときもアプリケーションコードを書いているエンジニアだけで簡単に対応できます。手作りなところは少ないので、仮に他の環境で動かしたくなってもあまり困らないのも良いですね。みなさんにもぜひ参考にしてもらえたら嬉しいです。
*1:Vercelも検討しましたが、バックエンドやデータベースのことも考慮した上で、すでにGoogleのFirebase Authenticationも利用していることもあってGoogleのサービスでまとめるという判断をしました。
*2:現在非推奨のContainer Registryが例として紹介されているのでご注意ください。Artifact Registryを使いましょう。
*3:GitHub Repository SecretsにService Accountのキーを登録せずに済んで嬉しい!
*4:この図はGoogle CloudのCertificate ManagerのドキュメントやServerless network endpoint group (NEG) のドキュメントに載ってる図を参考に描いています。
*5:2022年6月時点ではCertificate ManagerはまだGA前の機能なので注意。
id:stefafafan
マンガ投稿チームでWebアプリケーションエンジニアを務める。2015年7月入社。認定スクラムマスター(CSM)。
Twitter:@stefafafan GitHub:stefafafan
blog:stefafafan の fa は3つです
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。