👀

Renderでマイグレーションだけ実行したい時のプラクティス

に公開

背景

RenderでGo + PostgreSQLのアプリケーションを運用する際、マイグレーションだけ実行したいというケースがあります。
たとえば、migrations/migration.go のようなファイルをRender上で一度だけ走らせたい。しかし、RenderではWorkerサービスを作ると常時稼働扱いで課金対象になるため、単発の処理のためにWorkerを作るのは非効率です。

Herokuユーザー向けに補足

Herkokuだったら、Dynoが2つまで無料です。
マイグレーション用のDynoを作成して、一時的に有効にしてデプロイ後に無効にすれば済んでいました。

同じようなことをRenderでやろうと思ったら、お金がかかると判明しました。
『マイグレーション用のDyno』的な概念は『マイグレーション用のWorkerサービス』に相当します。
一瞬しか使わない『マイグレーション用のWorkerサービス』にWebサービスと同様の課金が発生してしまうというわけですね。。。

最後にちょろっと書いてますが、『CI/CDで外部から叩く』が一番独立性が担保できて良いですけどね。
今回の対応方法は恒久対応としては微妙だが、初期開発とかならありなんじゃないかなと思ってます。


RenderのWorkerサービスは常時課金対象

Renderにおいて、

  • Webサービス
  • Workerサービス

どちらも常時起動が前提となっており課金対象になります。

Workerはバックグラウンド処理などに使う前提なので、短時間のマイグレーションのために使うのはおすすめできません。


解決策:Webサービスで条件付き実行

一時的にWebサービスとしてマイグレーション処理を実行するという方法があります。

以下のようなコードを main.go に書いておくことで、環境変数を切り替えるだけでマイグレーションが実行可能です。

func main() {
    if os.Getenv("RUN_MIGRATION") == "true" {
        runMigrations()
        return
    }

    // 通常のWebサーバ起動
    router := setupRouter()
    router.Run(":" + os.Getenv("PORT"))
}

Renderの「環境変数」に RUN_MIGRATION=true を設定してデプロイすれば、
一度だけマイグレーションが走り、アプリケーションは即終了します。


マイグレーション後は変数をOFFにする

その後、Renderの環境変数から RUN_MIGRATION を削除または false に戻せば、通常どおりWebアプリとして起動します。


その他の方法

外部からマイグレーションを実行(おすすめ)

  • GitHub ActionsなどCI/CDを利用して、RenderのDBに外部から go runpsql コマンドでアクセス
  • これにより、Render内に一切Workerやマイグレーション用のサービスを持たずに済む

一時的なWorkerとして即削除(非推奨)

  • Workerを作って即削除しても、タイミングによっては課金対象になります

まとめ

方法 コスト おすすめ度
WebサービスでRUN_MIGRATION=trueにする 無料枠内で可 ◎ 開発初期など限定的に便利
Workerを作る 課金対象になる可能性あり △ 短期的には非効率
CI/CDで外部から叩く Renderには負担なし ◎ 安定運用向け

RenderはシンプルなPaaSなので、こうした小技を活用するとコストと利便性を両立できます。

Discussion