SmartHR Tech Blog

SmartHR 開発者ブログ

GCPを使ってPRごとに検証環境を用意した話

はじめに

こんにちは。プロダクトエンジニアグループ所属の@sato-s, @kawaです。普段はSmartHRのオプション機能の開発をしています。この記事では「GitHubのPull Requestごとに動作確認が可能な検証環境をGoogle Cloud上に構築する仕組み」を作った話をご紹介します!

背景

SmartHRでは2022年にインフラをAWSとHerokuからGoogle Cloudへ全面移行しました。(Google Cloudへの全面移行についてはGoogle Cloudの顧客事例として紹介していただき、2022年の Google Cloud Day: Digital ’22 でも登壇を行いました。)

以前はHerokuを利用していたこともあり、Herokuが提供するReview Appsというサービスを活用していました。
Heroku Review Appsとは、GitHubと連携しPull Request(PR)ごとに動作確認が可能な使い捨ての検証環境を自動で作成する機能です。 PRごとに自動あるいは手動トリガーで検証環境が構築され、割り振られたURLにアクセスすることで、アプリケーションの挙動やUIの確認をしたり、手動テストを実行したりすることができます。
通常、PR作成者以外のメンバーが動作確認を行う場合、PRのブランチをチェックアウトしローカルで開発環境を立ち上げる必要がありますが、Review Appsを使用すればローカルでの開発環境がなくても確認できます。特にPMやデザイナーなど、普段あまりローカルで開発環境を立ち上げないメンバーに確認をしてもらいたいときに便利な機能です。

SmartHRでもいくつかのチームでこの機能を利用していたのですが、Google Cloudに全面移行したこともあり、このReview Appsに相当する仕組みをGoogle Cloud上で実現できればstaging、productionとネットワークやミドルウェアなどの構成が揃った使い捨ての検証環境を構築することができて最高なのでは…!?という思いから数人のメンバーで構成の検討を始めました。

余談

実はもっと過去にはAWS上で似たような仕組みの構築をしていたこともあったそうです。
https://tech.smarthr.jp/entry/2017/03/01/112300
歴史は繰り返すのであった…。

Google Cloud版Review Appsをどこに作るか

SmartHRではproduction, staging, developmentと呼ばれる環境を用意しており、各環境はGoogle Cloudのプロジェクトのレベルで完全に分離されています。この内development環境は、SmartHRがAWSとHerokuからGoogle Cloudに移行する際の移行作業の検証のために使用されていたものでしたが、Google Cloudへの移行が済んだ後は各チームであまり利用されていない環境になっていました。
Google Cloud版Review Appsを構築するにあたりこのdevelopment環境を再利用することにしました。こうすることで、productionやstagingへの影響を出すことがなくなりますし、VPCや権限の設定を1から作る手間も省くことができます。

当初のやりかた

PRごとに検証環境の仕組みを作り始めた当初は以下のようなアーキテクチャを検討していました。

当初のやり方のアーキテクチャ

図中の”通常のアプリケーション”は、development環境にもとから存在するSmartHRのアプリケーションです。
この"通常のアプリケーション"はPRごとの検証環境を作った後も維持する必要があり、このアプリケーションを作るterraformの構成ファイルに対する変更も最小限にする必要がありました。そこで、このアーキテクチャではURL MapとCloud Runのサービスのみを共有し、target HTTPS proxyや証明書などのその他のリソースをPRごとに作ることで、PRごとの検証環境を実現することを目指しました。

具体的なPRごとの検証環境を作る手順は、このような流れになります。

  1. GitHubのPRからDockerのイメージを作成する
  2. DockerのイメージからCloud Runのリビジョンを作成し、そのリビジョンに特定のタグを付ける
  3. このPRのためのtarget HTTPS proxy, Backend, Serverless NEGを作成しておく。(このときServerless NEGの向き先をCloud Runのリビジョンの特定のタグにしておくことで、最終的に、ロードバランサーから、特定のPRから作られたCloud Runのリビジョンが参照可能になる)
  4. [PR_NUMBER].reviewapps.example.comというドメインとDNS認証用のTXTレコードをGoogle Cloud外のDNSサービスに登録
  5. *.[PR_NUMBER].reviewapps.example.comに対する証明書をGoogle CloudのCertificate Managerを使って作成
  6. 証明書とtarget HTTPS proxyをCertificate Mapを使って紐付ける
  7. Certificate Managerのdns-authorizationを使い証明書を有効化する

ところが、7の手順に大きな問題がありました。SmartHRでは基本的にインフラにGoogle Cloudを利用しているものの、DNSのみは別のサービスを利用しています。
そのためもあってか、Google Cloud上の証明書が有効になるのにとても時間が掛かり、PRごとの検証環境をつくるという運用に耐えられなさそうであることがわかりました。
また、環境を作る手順として、Google CloudとGoogle Cloud以外のサービスの両方を操作しなければならず、この手順が複雑で保守性が低いものになってしまう懸念がありました。

なぜドメインと証明書がPull Reuqestごとに必要なのか?

この手順で、なぜいちいちドメインを作成し、さらにそれに対する証明書が有効になるのを待つ必要があるのでしょうか?
reviewapps.example.comというドメインがあれば*.reviewapps.example.comのようなワイルドカード証明書を発行しておくことができます。通常のアプリケーションでは[PR_NUMBER].reviewapps.example.comのようにPRごとにサブドメインを変更することで、PRごとの環境を作成するということができます。

SmartHRではこの点が特殊で、ユーザーに[会社名].smarthr.jpのようなドメインを提供しています。SmartHRのアプリケーションのほとんどは、この[会社名]の部分のサブドメインに依存しており、[会社名]の部分がないと正しく動作しません。検証環境でも実際にはsample-inc.[PR_NUMBER].reviewapps.example.comのような会社名が入ったドメインにアクセスして検証する必要があります。

このため、PR1つ1つに対して*.[PR_NUMBER].reviewapps.example.comのようなワイルドカード証明書が必要となるのでした。

N Review Apps方式

N Review Apps方式アーキテクチャ

PRごとに証明書を発行しなければならないという問題のため、結局PRごとの検証環境は上のようなアーキテクチャで実現することになりました。このアーキテクチャでは、事前にNセットのドメイン・証明書、そしてロードバランサーを用意しておき、あるPRに対する検証環境を作成する際には、Nセットのどこかの向き先を、そのPRから作られた環境に向けるということだけをします。(社内ではこのやり方をN Review Apps方式と呼んていました)

事前に、reviewapps1というドメインでreviewapps1というタグの付いたCloud Runのリビジョンが参照できるようにロードバランサーを設定しておけば、特定のPRをreviewapps1というタグ付きでCloud Runにデプロイするだけで、参照可能になります。こうすることで、PRごとにドメインと証明書を作成するというステップを省くことができ、10分程度の比較的すくない待ち時間でPRごとの検証環境を作ることができるようになりました。

このやり方では必然的に同時にデプロイ可能なPRごとの検証環境はN個に制限されます。このため、PRができると勝手に上記の手順で検証環境が作成されるようなことはできませんでした。代わりに、検証環境の作成の際はGitHubのラベルを利用しています。予めreviewapps1〜reviewappsNまでのラベルを決めておき、特定のPRに対してreviewapps1のラベルを貼ると、reviewapps1の環境に対して、このPRがデプロイされることとなります。また、ラベルが外されたときやPRがマージされた時はreviewapps1の環境に対してクリーンアップが実施されます。

GitHubのラベルから検証環境を作っているイメージ

N Review Apps方式を実際に運用してみて

N Review Apps方式は当初、運用面で以下のような懸念がありました。

  • Nセットの上限が足りなくなったときどうするのか?
  • 異なるPRを別な人が同じ環境にデプロイしてしまうなどの事故が発生しないか

しかし、実際に運用してみると、そこまで大きな問題が無いことがわかりました。
SmartHRにはたくさんの開発者がいますが、多くのチームはピザ2枚ルールによって、8名以下の小人数になっています。各チームに対して1つか2つの検証環境を割り当てれば、多くの場合それで十分でした。
また、少人数のチームであることからPRごとの検証環境を作るという作業は多くの場合、個人で行われる訳ではなくチームの総意をもって行われるようでした。このため、異なるPRを別な人が同じ環境にデプロイしてしまうというようなことも発生しにくい状況となっていました。

まとめ

SmartHRではGCP移行後にHeroku Review Appsの代わりとなるものを作ろうとしていました。
当初は、PRごとの検証環境をオンザフライで作るアーキテクチャを検討していました。
しかし、[会社名].smarthr.jpのような会社固有のドメインをユーザーに提供しているというSmartHRの特性のため、PRごとにドメインと証明書をその場で用意することが困難でした。
そこで事前にNセットの環境を用意しておき、そのどこかの環境にPRをデプロイする仕組みをつくることで、PRごとの検証環境を用意することができました。運用上の懸念もあったものの、現在SmartHRでは、この方式で上手く検証環境を運用することができています。

We are hiring!

こんな検証環境を用意しているSmartHRで一緒に働きませんか!?
SmartHRではエンジニアを大募集しています!
詳しくは以下を御覧ください!

hello-world.smarthr.co.jp