背景
rails db:migrate 実行時に誤ってrails db:migrate:reset が実行され本番環境のデータが復旧までの1時間ほど消えた状態となった。
rails db:migrate:reset は以下を行う非常に危険なコマンドです:
- データベース削除 (db:drop)
- 再作成 (db:create)
- マイグレーション適用 (db:migrate)
- 初期データ投入 (db:seed)
本番・ステージング環境で実行すると データが完全に消失 するため、誤操作防止が必須です。
→改善案:本番やステージング環境で不要な危険なコマンドを使用できなくする。
前提:
・環境変数で環境を判定
独自の環境変数を利用し、環境を判断できることが条件です。
Docker 環境では .env ファイルに独自の環境変数を設定し、Rails アプリ内で利用
# .env
APP_ENV=production # 本番の場合
# APP_ENV=staging # ステージングの場合
# APP_ENV=development # 開発の場合
Docker Compose から Rails アプリに渡るので、アプリ側では ENV[“APP_ENV”] で判定可能です
方法1: Rake タスクを上書きして禁止する
lib/tasks/disable_dangerous_tasks.rake を作成し、APP_ENV が production または staging の場合に危険タスクを無効化します。
# lib/tasks/disable_dangerous_tasks.rake
app_env = ENV["APP_ENV"]
if %w[production staging].include?(app_env)
# migrate:reset を完全禁止
Rake::Task["db:migrate:reset"].clear
Rake::Task.define_task("db:migrate:reset") do
abort "❌ ERROR: db:migrate:reset is disabled in #{app_env} environment!"
end
# 他の危険タスクも同様に禁止
%w[db:drop db:schema:load db:setup].each do |task|
if Rake::Task.task_defined?(task)
Rake::Task[task].clear
Rake::Task.define_task(task) do
abort "❌ ERROR: #{task} is disabled in #{app_env} environment!"
end
end
end
end
方法2: 環境設定ファイルでガードを追加(保険)
config/application.rb または config/environments/production.rb に保険として追加できます。
if defined?(Rake)
if %w[production staging].include?(ENV["APP_ENV"])
if Rake.application.top_level_tasks.grep(/db:(migrate:reset|drop|schema:load|setup)/).any?
abort "❌ Forbidden task detected in #{ENV["APP_ENV"]} environment!"
end
end
end
方法3: Docker コンテナ側で alias 無効化
より安全にするなら、コンテナ内の .bashrc や .zshrc に alias を設定しておきます。
alias "rails db:migrate:reset"='echo "❌ ERROR: db:migrate:reset is disabled in this environment" && exit 1'
alias "rails db:drop"='echo "❌ ERROR: db:drop is disabled in this environment" && exit 1'
✅ 推奨構成
- .env で APP_ENV を production / staging に設定
- 方法1(タスク上書き)+ 方法2(保険ガード)で二重ロック
- alias は運用側で必要に応じて適用
動作確認
# 本番環境
$ APP_ENV=production docker-compose exec oripa_api rails db:migrate:reset
❌ ERROR: db:migrate:reset is disabled in production environment!
# ステージング環境
$ APP_ENV=staging docker-compose exec oripa_api rails db:drop
❌ ERROR: db:drop is disabled in staging environment!
# 開発環境(従来通り実行可能)
$ APP_ENV=development docker-compose exec oripa_api rails db:migrate:reset
# => DBがリセットされる