Render の Preview Environments で Pull Request ごとの実行環境を自動生成するには

2022/06/03に公開

RenderのBlueprintとPreview Environmentsを使うと、GitHubでpull request が作成される度に、pull requestごとに独立した環境を自動生成することができます。 Blueprintはインフラの構成をYAMLで記述したものでinfracture as codeに役立ちます。Preview EnvironmentはBlueprintをもとに、pull requestごとに本番と同じ環境(サービス、データベースなどを含めた)のクローンを作り、動作確認や認識の共有などに役立てることができます。

Preview Environments

Render

RenderはPaaSです。 同様のPaaSとしてはHerokuが有名で歴史があります。RenderはHerokuに比べるとだいぶ後発な分、洗練されていて使い勝手は良いです(個人の感想です)。RenderにはPostgreSQL、Redisといったデータベース、“フル機能”のCronも使える他、CloudflareによるDDoSプロテクションも備わっています。Herokuとの比較についてはRender vs Herokuにまとめられています。

https://render.com

https://render.com/render-vs-heroku-comparison

Blueprint

Blueprintは、Render のインフラ(サービス(WebService、StaticSite)、データベース、Environment Group)をコードとして render.yaml ファイルで定義したものです。 render.yaml をリポジトリに含めて変更をPushすると、Renderは render.yaml をみて自動的にインフラを更新します。RenderではこのようにしてInfrastructure as Code (IaC)を実現します。

https://render.com/docs/infrastructure-as-code

Preview Environments

Preview Environmentsは、Blueprintの機能の1つで、pull requestごとにBlueprintから本番環境のクローン(サービス(WebService、StaticSite)、データベース、Environment Groupを含む)を自動的に作成することで、pull requestごとに独立したテスト実行環境を提供します。 独立した環境なので、1つのステージング環境を共有するときのように他への影響を気にすることなテストをすることができます。作成された環境はpull requestがマージされるかクローズされると自動で破棄されます。また有効期限を設定して、一定時間プッシュされないと自動で破棄することもできます。

https://render.com/docs/preview-environments

RailsアプリでPreview Environmentsを利用する

RailsアプリでPreview Environmentsを利用するには、まずBlueprintを作成して、Renderにアプリをデプロイした上で、Preview Environmentsの設定を追加します。

Railsアプリの作成

簡単なRailsアプリを作成して、実際の手順を確認します。

https://github.com/takeyuweb/rails-render-demo

本番環境/プレビュー環境で環境変数を変更するデモをしたいので、 dotenv-railsを使いました。この後の手順でデプロイ時に適切な環境変数を設定する方法をあわせて確認します。

https://github.com/takeyuweb/rails-render-demo/blob/31cf9805ab4491d63baa63eefbf819b68a6ff6e9/Gemfile#L74
https://github.com/takeyuweb/rails-render-demo/blob/31cf9805ab4491d63baa63eefbf819b68a6ff6e9/.env.sample#L1
https://github.com/takeyuweb/rails-render-demo/blob/31cf9805ab4491d63baa63eefbf819b68a6ff6e9/app/views/layouts/application.html.erb#L13-L17

Renderのための修正

公式のドキュメント(Update Your App For Render - Getting Started with Ruby on Rails on Render)参考にRender向けに変更を加えます。

https://render.com/docs/deploy-rails#update-your-app-for-render

実際の変更内容はコミットを確認してください。

https://github.com/takeyuweb/rails-render-demo/commit/6dd7ab5b1c08c5f335181a127d377eb9235d4f9b

Blueprintの作成

render.yaml をプロジェクトのルートに作成します。 以下はPostgreSQL 14のデータベースと、RailsのWebアプリケーションサーバー(Puma)でWebアプリを構成するコードです。

render.yaml
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をクリックして進みます。
New Environment Group

Add Secret File.env を追加します。ここで指定したファイルは実行時にルートディレクトリ直下でアクセスできるので、他の設定無しにdotenv-railsで読み込むことができます。
Add Secret File

Renderにデプロイ

ルートに render.yaml を配置したリポジトリを登録すると、Renderは記載されている内容に従って必要なデータベースの作成やアプリのビルドなどを行い、デプロイが完了します。

Blueprints ナビゲーションから Blueprints 管理画面を開き、 New Blueprint Instanceをクリックして進みます。
New Blueprint Instance

GitHubまたはGitLabのリポジトリを選びます。
リポジトリを指定

するとリポジトリの内容が確認され、render.yaml が検出されます。render.yaml がない場合は進めません。
自動でrender.yamlを検出する

Apply をクリックするとリソースの作成が開始されます。しばらくすると完了します。失敗した場合は失敗内容をエラーログから確認して際デプロイしましょう。
デプロイ成功

完了したら https://<サービス名>.onrender.com でアクセスすることができます。
アクセスできました

Preview Environmentsを有効にする

Preview Environmentsは、Blueprintの機能の1つで、pull requestごとにBlueprintをもとにクローンを作成します。有効にするにはBlueprint(render.yaml)に変更を加えてpushします。 実際の変更内容は次のコミットを参考にしてください。

https://github.com/takeyuweb/rails-render-demo/commit/dc40a9fad7628fc656d2b4ce8670f72402bfb05f

Blueprintの更新

render.yamlpreviewsEnabled: true を追加するだけです。 その他の、previewsExpireAfterDays: previewPlan: initialDeployHook: は任意です。

render.yaml
# 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'
    # (省略)
./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を配置することになります。例えば次のようにします。

./bin/render-build.sh
#!/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を用意し、ビルド中に適切なものを選択しています。
dotenv-prev と dotenv-prod を作成

リポジトリにpush

GitHub(またはGitLab)にpush するとRenderは自動でBlueprintの更新を反映し、Preview Environmentが有効になります。 Renderダッシュボード上で確認することができます。

Update Blueprint Stale PR Server Expiration: 3 days

Pull RequestのPreview Environmentを作成

pull requestを作成すると、Renderはpull requestのコミットの render.yaml を使ってBlueprintを登録し、サービス、データベースなどのリソースを作成します。 作成が完了するとGitHub上にPreview EnvironmentのURLを表示します。以降、pull requestにpushがあると最新のコミットを使ってサービスを更新します。

Pull Requestに

RenderダッシュボードのBlueprintsを確認すると、pull request に対応したBlueprintが自動作成されています。

Blueprintが追加されている

作成された環境にアクセスしてテストなどに利用することができます。

Preview Environment の service

気になったこと

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年後半には東京リージョンを追加予定としています。

https://render.com/docs/regions

https://feedback.render.com/features/p/tokyo-region

まとめ

RenderのBlueprintとPreview Environmentsを使うことで、pull requestごとに独立したプレビュー環境を自動生成することができました。 Blueprintでインフラの構成を管理していれば、かんたんに有効にすることができます。その場で動作確認などが行えるのはレビューや、お客様への共有などでとても便利です。ただし費用が発生してしまうので作りっぱなしにならないように注意しましょう。

今回はBlueprint管理外のEnvironment GroupのSecret Filesを利用して、プレビュー環境と本番環境での .env の出し分けを行いましたが、この方法は問題もあります。

  • 本番環境の秘密情報とプレビュー環境の秘密情報が併記されていて人為的ミスで取り違えるのが怖い
  • “Blueprint管理外のEnvironment Group”がすでに気持ち悪い

他に良い方法があれば試してみたいところです。

タケユー・ウェブ株式会社

Discussion