ステージング環境データベースのバックアップを取得してローカル環境に流したいということがあり本題のことをやるに至りました。
利用技術のバージョンは以下です。今回DBはPostgreSQLに限りたいと思います
技術名称 | バージョン |
---|---|
Ruby | 3.2.2 |
Rails | 7.0.4.3 |
PostgreSQL | 14.6 |
全体の流れ
- 環境構築(今回Railsを動かしているイメージにpostgresql-client-14が単純には入らなかったのでその解説)
- バックアップファイルの作成
- バックアップしたファイルをS3にアップロード
といった流れで行います。
1. 環境構築
PostgreSQLでバックアップファイルを作成するために pg_dump
コマンドを利用します。
Dockerコンテナ内で開発を行っている場合には、DBのコンテナとRailsのコンテナが異なっており、Railsコンテナにはpostgresql-clientがなく、pg_dumpコマンドを利用できないといったことがあるかも知れません。
pg_dumpコマンドがすでに利用できる環境の方は、この章を飛ばしていただいて構いません。ぜひ次の章へ バックアップファイルを作成
postgresql-clientのインストール
pg_dumpコマンドを使える様にするために、RailsのDockerfileのapt install
を実行している箇所に、以下のようにpostgresql-client
を追加します。
RUN apt update -qq && \
apt install -y build-essential vim libvips locales tzdata \
postgresql-client-14 #←これ追加
注意点としては、必ず実際に利用している PostgreSQLのバージョンに合わせたバージョンをインストールしてください。
バージョンが異なる場合には、pg_dump
ができない場合があります。
しかし、2023年4月時点では、PostgreSQLの14系をインストールするには、1つ工夫が必要です。
上記の様にpostgresql-client-14
を追加するだけでは、「14系が見つからない」というエラーが発生してインストールができません。
postgresql-client-14をインストールするために
結論apt install -y postgresql-client-14
をする前に以下の4行ほど追加しておきます。
FROM ruby:3.2.2 AS base
# ...この辺りにもみなさん数行あるだろうけど関係ないので省略
# ここから追加
RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
gpg --dearmor -o /usr/share/keyrings/postgresql-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/postgresql-keyring.gpg] http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | \
tee /etc/apt/sources.list.d/postgresql.list
# 追加はここまで
RUN apt update -qq && \
apt install -y build-essential vim libvips locales tzdata \
postgresql-client-14
追加した4行についてざっくり解説します。
1行目は、curlコマンドでhttpリクエスト送信してPostgreSQLリポジトリの公開鍵をダウンロードしています。
2行目は、gpgコマンドで先にダウンロードした鍵をデコードして/usr/share/keyrings/postgresql-keyring.gpg
ファイルに保存しています。
3,4行目は、PostgreSQLパッケージのAPTリポジトリをechoで出力して、その出力をteeコマンドで /etc/apt/sources.list.d/postgresql.list
ファイルに書き込んでいます。
参考: https://linuxways.net/debian/how-to-install-postgresql-14-on-debian-11/
これでpg_dumpコマンドに必要なpostgresql-clientのインストールができたかと思います。
バックアップファイルの作成
今回、バックアップの処理はサービスクラスで行う様にしました。
これは私がRakeタスクでバックアップ取りたいと思い、「Rakeタスクからは対応するサービスクラスを呼び出すだけに留める」という方針で開発しているため、サービスクラスに書いております。
全体のコードをとりあえず載せておきます。長いので折りたたみ式です。
全体のコード
class Tasks::Tools::DbBackupService
def initialize
@filename = "backup.sql"
end
def execute
backup
upload
Rails.logger.debug `rm -f tmp/#{@filename}`
ServiceResponse.success(message: "バックアップが完了しました")
end
private
def backup
db_config = Rails.configuration.database_configuration[Rails.env]
cmd = `PGPASSWORD="#{db_config["password"]}" \
pg_dump -F p -v \
-U #{db_config["username"]} \
-h #{db_config["host"]} \
-d #{db_config["database"]} \
-p #{db_config["port"]} \
-f tmp/#{@filename}`
end
def upload
s3_client.put_object(
bucket: Rails.application.credentials.aws[:s3_user][:bucket],
body: File.open("tmp/#{@filename}"),
key: @filename
)
end
def s3_client
Aws::S3::Client.new(
region: Rails.application.credentials.aws[:s3_user][:region],
credentials: Aws::Credentials.new(
Rails.application.credentials.aws[:s3_user][:access_key_id],
Rails.application.credentials.aws[:s3_user][:secret_access_key]
)
)
end
end
特に重要な箇所のbackupメソッドだけ簡単に紹介します。
まずは以下がコードです。
def backup
db_config = Rails.configuration.database_configuration[Rails.env]
cmd = `PGPASSWORD="#{db_config["password"]}" \
pg_dump -F p -v \
-U #{db_config["username"]} \
-h #{db_config["host"]} \
-d #{db_config["database"]} \
-p #{db_config["port"]} \
-f tmp/#{@filename}`
Rails.logger.debug cmd
end
db_config
変数には起動している環境のDB情報が入っています。
その情報を用いてpg_dumpを行います。
pg_dumpで指定しているオプションは
-
-F p
で平文のSQLスクリプトファイルの出力フォーマットを指定 -
-v
で、詳細なオブジェクトコメント、開始時刻、終了時刻をダンプファイルに、進行状況メッセージを標準エラーに出力させます(ログを表示したくない場合はこのオプションは利用しないのがいいかなと) -
-f
でバックアップをファイルの置き場を指定しています。- 今回はtmpフォルダに
backup.sql
のようなファイル名で置いています。
- 今回はtmpフォルダに
- 先頭の
PGPASSWORD
入力を省くため、パスワードの環境変数です。値を埋め込んでいます
pg_dumpコマンドのオプションについての公式サイトはこちら
https://www.postgresql.jp/document/14/html/app-pgdump.html#PG-DUMP-OPTIONS
これでバックアップの完了です。
今はtmp/フォルダにバックアップしたファイルが設定されています。
ローカル環境であればそれでいいですが、ステージング環境などのtmpフォルダに置かれてもローカルに持ってくるのが大変なので次にS3にアップします。
バックアップしたファイルをS3にアップロード
以下のGemを利用してS3との接続をします。使用したバージョンは 1.121.0
です。
gem "aws-sdk-s3"
以下でtmpフォルダあるバックアップしたファイルをアップロードしています。
def upload
s3_client.put_object(
bucket: Rails.application.credentials.aws[:s3_user][:bucket],
body: File.open("tmp/#{@filename}"),
key: @filename
)
end
def s3_client
Aws::S3::Client.new(
region: Rails.application.credentials.aws[:s3_user][:region],
credentials: Aws::Credentials.new(
Rails.application.credentials.aws[:s3_user][:access_key_id],
Rails.application.credentials.aws[:s3_user][:secret_access_key]
)
)
end
こちらはしっかりと、他人から閲覧できないS3バケットに置くようにしましょう。
また、私はアップロードが完了したら以下の様なコードで、tmpフォルダにあるバックアップファイルは削除しています。
Rails.logger.debug `rm -f tmp/#{@filename}`
tmpフォルダに置きっぱなしも危険なので消しておきましょうね。
終わりに
以上で、初めに紹介した流れの3ステップが完了です。
個人的には、今回の本題ではないですが、postgresql-client-14のインストールが大変でした。
もし詰まっている方がいたら、この記事が参考になればと思います。