Render の Preview Environments で Pull Request ごとの実行環境を自動生成するには
RenderのBlueprintとPreview Environmentsを使うと、GitHubでpull request が作成される度に、pull requestごとに独立した環境を自動生成することができます。 Blueprintはインフラの構成をYAMLで記述したものでinfracture as codeに役立ちます。Preview EnvironmentはBlueprintをもとに、pull requestごとに本番と同じ環境(サービス、データベースなどを含めた)のクローンを作り、動作確認や認識の共有などに役立てることができます。
Render
RenderはPaaSです。 同様のPaaSとしてはHerokuが有名で歴史があります。RenderはHerokuに比べるとだいぶ後発な分、洗練されていて使い勝手は良いです(個人の感想です)。RenderにはPostgreSQL、Redisといったデータベース、“フル機能”のCronも使える他、CloudflareによるDDoSプロテクションも備わっています。Herokuとの比較についてはRender vs Herokuにまとめられています。
Blueprint
Blueprintは、Render のインフラ(サービス(WebService、StaticSite)、データベース、Environment Group)をコードとして render.yaml
ファイルで定義したものです。 render.yaml
をリポジトリに含めて変更をPushすると、Renderは render.yaml
をみて自動的にインフラを更新します。RenderではこのようにしてInfrastructure as Code (IaC)を実現します。
Preview Environments
Preview Environmentsは、Blueprintの機能の1つで、pull requestごとにBlueprintから本番環境のクローン(サービス(WebService、StaticSite)、データベース、Environment Groupを含む)を自動的に作成することで、pull requestごとに独立したテスト実行環境を提供します。 独立した環境なので、1つのステージング環境を共有するときのように他への影響を気にすることなテストをすることができます。作成された環境はpull requestがマージされるかクローズされると自動で破棄されます。また有効期限を設定して、一定時間プッシュされないと自動で破棄することもできます。
RailsアプリでPreview Environmentsを利用する
RailsアプリでPreview Environmentsを利用するには、まずBlueprintを作成して、Renderにアプリをデプロイした上で、Preview Environmentsの設定を追加します。
Railsアプリの作成
簡単なRailsアプリを作成して、実際の手順を確認します。
本番環境/プレビュー環境で環境変数を変更するデモをしたいので、 dotenv-rails
を使いました。この後の手順でデプロイ時に適切な環境変数を設定する方法をあわせて確認します。
Renderのための修正
公式のドキュメント(Update Your App For Render - Getting Started with Ruby on Rails on Render)参考にRender向けに変更を加えます。
実際の変更内容はコミットを確認してください。
Blueprintの作成
render.yaml
をプロジェクトのルートに作成します。 以下はPostgreSQL 14のデータベースと、RailsのWebアプリケーションサーバー(Puma)でWebアプリを構成するコードです。
databases:
- name: rails-render-demo
databaseName: rails_render_demo
user: rails_render_demo
plan: starter
region: singapore
postgresMajorVersion: 14
services:
- type: web
name: rails-render-demo
env: ruby
plan: starter
region: singapore
buildCommand: './bin/render-build.sh'
startCommand: 'bundle exec puma -C config/puma.rb'
envVars:
# 環境変数 DATABASE_URL に databases で定義した rails-render-demo データベースの接続情報を格納する
# Railsのconfig/database.ymlでこの環境変数を使ってデータベースに接続する
- key: DATABASE_URL
fromDatabase:
name: rails-render-demo
property: connectionString
# Environment Group rails-render-demo_dotenv の環境変数・Secret Filesを使う
- fromGroup: rails-render-demo_dotenv
Secret Files を設定する
RenderではSecret Filesの仕組みにより、.env
をリポジトリに含めずに、アプリのビルド時や実行時に .env
を配置することができます。 dotenv-rails
により、ルートに.env
を配置することで環境変数を設定できるので、これを利用して RAILS_MASTER_KEY
などの秘密情報をアプリに注入します。
Environment Group を作成
Secret Filesの設定はEnvironment Groupsで行います。 render.yaml
で指定したEnvironment GroupをRenderのダッシュボードから作成します。手動で作成するためBlueprintの管理外のリソースになりますが、Blueprintから参照することは可能です。
Env Groups
ナビゲーションから Environment Groups 管理画面を開き、 New Environment Group
をクリックして進みます。
Add Secret File
で .env
を追加します。ここで指定したファイルは実行時にルートディレクトリ直下でアクセスできるので、他の設定無しにdotenv-rails
で読み込むことができます。
Renderにデプロイ
ルートに render.yaml
を配置したリポジトリを登録すると、Renderは記載されている内容に従って必要なデータベースの作成やアプリのビルドなどを行い、デプロイが完了します。
Blueprints
ナビゲーションから Blueprints 管理画面を開き、 New Blueprint Instance
をクリックして進みます。
GitHubまたはGitLabのリポジトリを選びます。
するとリポジトリの内容が確認され、render.yaml
が検出されます。render.yaml
がない場合は進めません。
Apply
をクリックするとリソースの作成が開始されます。しばらくすると完了します。失敗した場合は失敗内容をエラーログから確認して際デプロイしましょう。
完了したら https://<サービス名>.onrender.com
でアクセスすることができます。
Preview Environmentsを有効にする
Preview Environmentsは、Blueprintの機能の1つで、pull requestごとにBlueprintをもとにクローンを作成します。有効にするにはBlueprint(render.yaml)に変更を加えてpushします。 実際の変更内容は次のコミットを参考にしてください。
Blueprintの更新
render.yaml
に previewsEnabled: true
を追加するだけです。 その他の、previewsExpireAfterDays:
previewPlan:
initialDeployHook:
は任意です。
# Preview Environments を有効にしてPRごとにPreview環境を作成する
previewsEnabled: true
# 最後にpushしてから3日間pushがなければPreview環境を削除する
previewsExpireAfterDays: 3
databases:
- name: rails-render-demo
# (省略)
# Preview環境で使用する料金プラン
previewPlan: starter
# (省略)
services:
- type: web
# (省略)
# Preview環境で使用する料金プラン
previewPlan: starter
# (省略)
# 最初のデプロイの時に実行するスクリプト。たとえば `bundle exec rails db:seed` でテストデータを投入するなど。
initialDeployHook: './bin/render-initial-deploy.sh'
# (省略)
#!/usr/bin/env bash
set -o errexit
bundle exec rails db:seed
Preview 環境か本番環境かを判定する
ビルドスクリプト中やアプリケーション中で、現在実行されているのがPreviewか本番かを判定するには IS_PULL_REQUEST
環境変数を使用します。 たとえば外部サービスのAPIキーはほとんどの場合本番用のキーとプレビュー用のキーは別にします。Blueprintで環境変数を定義している場合は、previewValueでプレビュー用の値を指定できますが、APIキーなどBlueprintに直接記載できない場合、ビルド時にPreviewか本番かを判定して適切な環境変数やSecret Fileを配置することになります。例えば次のようにします。
#!/usr/bin/env bash
set -o errexit
# .env.production だと dotenv-rails が RAILS_ENV=productionの時に選択してしまうのでこの名前
echo "copying .env"
if [ $IS_PULL_REQUEST = "true" ]; then
cp dotenv-prev .env
else
cp dotenv-prod .env
fi
# (省略)
上記の ./bin/render-build.sh
では本番用とプレビュー用のSecret Fileを用意し、ビルド中に適切なものを選択しています。
リポジトリにpush
GitHub(またはGitLab)にpush するとRenderは自動でBlueprintの更新を反映し、Preview Environmentが有効になります。 Renderダッシュボード上で確認することができます。
Pull RequestのPreview Environmentを作成
pull requestを作成すると、Renderはpull requestのコミットの render.yaml
を使ってBlueprintを登録し、サービス、データベースなどのリソースを作成します。 作成が完了するとGitHub上にPreview EnvironmentのURLを表示します。以降、pull requestにpushがあると最新のコミットを使ってサービスを更新します。
RenderダッシュボードのBlueprintsを確認すると、pull request に対応したBlueprintが自動作成されています。
作成された環境にアクセスしてテストなどに利用することができます。
気になったこと
RAILS_ENV="preview" はできない?
RAILS_ENV="production"
固定 で上書きができないようでした。
Preview Environments の請求はどうなる?
リソースが起動していた延べ時間(秒単位)に応じた従量課金になります。 たとえばデータベースとWebServiceそれぞれStarterプラン($7.00/月)で、1日起動していたPreview Environmentが100個あれば 7[ドル]÷31[日]×2[リソース]×100[個]×1[日]=45ドル
東京リージョンはある?
2022年6月3日現在の対応リージョンは、オレゴン・フランクフルト・オハイオ・シンガポールで東京はありませんが、2022年後半には東京リージョンを追加予定としています。
まとめ
RenderのBlueprintとPreview Environmentsを使うことで、pull requestごとに独立したプレビュー環境を自動生成することができました。 Blueprintでインフラの構成を管理していれば、かんたんに有効にすることができます。その場で動作確認などが行えるのはレビューや、お客様への共有などでとても便利です。ただし費用が発生してしまうので作りっぱなしにならないように注意しましょう。
今回はBlueprint管理外のEnvironment GroupのSecret Filesを利用して、プレビュー環境と本番環境での .env
の出し分けを行いましたが、この方法は問題もあります。
- 本番環境の秘密情報とプレビュー環境の秘密情報が併記されていて人為的ミスで取り違えるのが怖い
- “Blueprint管理外のEnvironment Group”がすでに気持ち悪い
他に良い方法があれば試してみたいところです。
Discussion
Tokyo regionは結局先延ばしされてるみたいですね...笑
悲しい!