はじめに
本番用と開発用のDBをろくに分けずに製作していた、自作アプリのデータベースを間違ってreset
してしまった(しかもバックアップも取っていなかった)ので、再発防止のための戒めと、環境ごとにデータベースを分ける&データベースのバックアップを取得する方法の備忘録です。
使用環境
- Ruby 3.3.1
- Rails 7.1.3
- Fly.io(本番環境)
- Docker(開発環境)
- PostgreSQL(データベース)
そもそも、なぜDBのデータ消えちゃったの?
上記の方とほぼ同じでテスト用のDBを作成しようとしている中でエラーが発生し、AIに解決方法を訊いたらbin/rails db:reset
のコマンドを提案されました。これを安易に実行してしまったのが原因。
警告もなく「これで成功します!」といつものノリで言われたまま、考えなしに実行したらデータベースのデータが全て消えてしまいました。
よく言われる「AIに提示されたコマンドを意味のわからないまま使ってはいけない」というのはこういうことが起こるからだよな……と今回は身を持って大反省。
AIによく知らないコマンドを提示されたら、わからないまま入力せず必ず調べること。
私の場合は幸いなことに、個人開発の時点で大失敗して反省できたのはラッキーでした。
万が一、会社やチーム開発でこういった自体が起こったときは、すぐに関係者と上司に報告しよう(怖いけど)。
ただ開発したアプリのデータベースが継続的な運用・保守に適していない状態で、特にデータを復元できなくなってしまったことは手痛かったので、今回の反省を踏まえてバックアップを取得できる環境を整えることにしました。
対策その1. 開発環境で入力したデータは開発用DBに登録する
現在、本番環境のデータベース(production)を開発時にも併用している状況なので、開発環境で入力したデータは開発用DB(development)に登録されるように、database.ymlで接続先を環境ごとに分離します。
# database.yml
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV['DB_USERNAME'] %>
password: <%= ENV['DB_PASSWORD'] %>
host: <%= ENV['DB_HOST'] %>
port: <%= ENV['DB_PORT'] %>
sslmode: disable #fly.ioのデータベースはsslmodeでないと外部から接続できないため使用
development:
<<: *default
database: development環境のデータベース名
test:
<<: *default
database: test環境のデータベース名
production:
<<: *default
database: production環境のデータベース名
# もとは「DATABASE_URL」を直接ここに入力していましたが、接続するDBをデータベース名で分離します
開発用とテスト用のDBを作成する
- DBを作成するためのコマンドを入力する
createdb -U ユーザー名 -h ホスト名 development環境のデータベース名
createdb -U ユーザー名 -h ホスト名 test環境のデータベース名
- DBをマイグレーションするためのコマンドを入力する(コンテナ内で)
RAILS_ENV=development bin/rails db:migrate
RAILS_ENV=test bin/rails db:migrate
上記の通りに実行してからDockerを再起動すると、本番環境で入力した内容は本番用のDBに、開発環境での入力内容は開発用のDBに登録されるように分離されました。
ついでにRSpecテスト用のDBを作成できました(本来の目的)。
対策その2. DBの操作前は必ずバックアップを取得する
DBを操作するようなことがある場合、作業前にdump
ファイルを取得しておくと安心。
ベテランの方ほど、こういった万が一の事故防止を徹底しているようです。見習います。
pg_dump
PostgresSQLデータベースをバックアップするユーティリティ。
PostgresSQLのバックアップについては他にも方法がいくつかありますが、今回はこちらを使いました。
pg_dump -U ユーザー名 -h ホスト名 -d バックアップを取得するデータベース名 -f backup.sql
上記を入力後、求められるデータベースのパスワードを打ち込めば、backup.sql
ファイルが生成されます。
backup.sql
ファイルは再度コマンドを入力すると上書きされるので、別々に残したい場合は下記のようにタイムスタンプを付けると良さげです。
念のために、日次で取得しておくことも大切。
-f backup_$(date +"%Y%m%d%H%M%S").sql
DBファイルは機密情報の塊なので、.gitignore
に記述してGitHubのリモートリポジトリに公開されないように設定しておきましょう。
# .gitignore
backup.sql
バックアップファイルのデータをリストアしたい時は、下記のように入力します。
psql -U ユーザー名 -h ホスト名 -d リストア先のデータベース名 -f backup.sql
あとがき
本番環境のデータを抹消した上に復元もできなくなってしまったという大失敗ですが、おかげで就職前にデータベース周りを再勉強できたこと、何よりも「AIの言うことを鵜呑みにする」典型的失敗パターンを経験できたのは良かったのかなと思います。
もっと酷ければプログラムが壊れてしまったりアプリ全体が動かなくなったりするようなので、AIが堂々と提示してくるコマンドは必ずどんなコマンドかよく調べて理解してから使おうね……という、とても今更な学びと戒めでした。
最後までご覧いただき、ありがとうございました!
参考リンク