想定した環境
タイトルの「開発」環境と言っている部分の想定は、
- 何らかのCI/CD環境を用いRailsアプリをクラウドなりオンプレの実環境へデプロイをする
- 一般的な「開発/dev/development」→「ステージング/stg/staging」→「運用/prd/prod/production」といった環境の流れを想定
- この「開発」用途の環境であり、デプロイするたびにデータベース丸ごと壊し初期化して良い、というかしたい
-
RAILS_ENV
のdevelopment
/production
とは別の話、「開発」環境だけどRAILS_ENV=production
である - そして初期化されたクリーンな状態で動作テストをしていく
- 「運用」用途でデータベースの内容を維持していくものは対象にしてはいない
データベースを破壊すのに困ること
まず初期化だがrailsのコマンドで行おうとするとrails db:reset
になると思う。そして、これを阻む諸々がある。
データベース破壊保護
そもそもRAILS_ENV=production
の場合、Rails5以降では、データベース破壊系コマンドに対する保護が入っているので、DISABLE_DATABASE_ENVIRONMENT_CHECK=1
を設定する必要がある。
Spring preloader
また、Rails4.1以降プリローダーとしてSpringが入り、これがrails
コマンドの実行を阻むので、DISABLE_SPRING=1
を指定する必要がある。
PostgreSQL 13
ここは、PostgreSQL限定の話になるが、該当データベースに対してコネクションが貼られた状態の場合、単純にはDROP DATABASE
できない仕様に変わっており(12→13)、特にCI/CDの様な形でアプリケーションプロセスが動いている状態ではdropできなくなっている。ここでPostgreSQL側はWITH (FORCE)
という強制実行のオプションを付与しdropできる様になっているが、rails側が生成するクエリーにはそのオプションが付与されないのでdb:reset
の実行では基本的に初期化できない(アプリケーションのデプロイによる再起動やタイムアウトでコネクションが切れていた場合に稀に成功するので悩む)。
上記の記事の様にモンキーパッチを当てて対処するのもあるかもしれませんが、メンテナンスの事を考えてCI/CD側のステップで行うというのが良いと思う。
結果
実際のCI/CD実装によるかと思うのですが、次のようなCLIコマンド/環境変数を実行する感じになる(あくまでもシェルスクリプト的なイメージ例)
# PostgreSQLの場合データベース初期化
PGPASSWORD={何らかの機密情報ストアー系から取得し環境変数で指定} \
psql -h ${POSTGRES_HOST} -U ${POSTGRES_USER} template1 \
-c 'DROP DATABASE IF EXISTS \"${POSTGRES_DB}\" WITH (FORCE)'
# Rails側での初期化処理
RAILS_ENV=production \
RAILS_MASTER_KEY={何らかの機密情報ストアー系から取得し環境変数で指定} \
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 \
DISABLE_SPRING=1 \
bundle exec rails db:reset
もしかしたら、使っているライブラリーや環境によっては他の環境変数などの設定が必要かも。