Docker+Rails6+cronでPostgreSQLのバックアップを別サーバーに保存する

最初からRailsに備わってくれていてもいいのに、と思うバックアップ機能。

はっきりいってDockerとcronの相性は悪いです。でも、ちゃんと実装できました。
情報が結構少なめで、やや苦戦しました。

環境

  • Docker
  • Rails6
  • PostgreSQL

やるべきこと

  • Railsにバックアップのタスクを登録
  • GemであるところのWheneverを導入
  • コンテナ上でcrontabを稼働させる

今回はこれで。

今回のハイライトです。アプリケーションコンテナ内にcronを同時展開させるのは悪手とされています。できることならcron専用のコンテナを建てる方が安定稼働・拡張性の面で好ましいと思います。

  • Railsコンテナ内にcronを設置する(あんまりよくない)
  • cronは自動起動ではなく管理画面から手動で起動させる
  • ダンプファイルはFTP転送

実装の流れ

さて、中身ですが、今回は先述の通りWheneverを使います。Wheneverはcrontabを生成してくれるGemで、schedule.rbに記載した情報をもとにcrontab -e 的なことをしてくれます。WheneverはGemfileに追記、あとcronもインストールするようにDockerfileに書いておきます。

GitHub – javan/whenever: Cron jobs in Ruby

次に、Railsの外部からバックアップを実行できるようにRailsにタスクを登録しておきます。このタスクをcronで実行するというわけですね。処理の内容としてはpg_dumpとftp転送です。

あとはcronで定期的にRailsタスクを呼び出せば自動バックアップが完成。
cronは手動起動できるように管理画面にスイッチを追加します。

全体の処理の流れとしては単純ですし、構成もわりとシンプルです。

全部は書きませんが、schedule.rbはこんな感じです。

require File.expand_path(File.dirname(__FILE__) + "/environment")
require 'active_support/core_ext/time'
set :output, "/var/log/cron.log"

set :environment, ENV["RAILS_ENV"]
def jst(time)
  Time.zone = 'Asia/Tokyo'
  Time.zone.parse(time).localtime($system_utc_offset)
end
ENV.each { |k, v| env(k, v) }

every 1.day, at: jst('0:00 am') do
  rake "task_backup:backup"
end

【Ruby on Rails】whenever を使って定期的にバッチ処理を行う – きゃまなかのブログ

wheneverで時刻を設定する際システムで設定されているのとは別のタイムゾーンを使用する | ⬢ Appirits spirits

cronでpg_dumpを実行する場合、cron先輩がパスワードがわからず0byteファイルが量産されてしまうので、1ライナーでパスワードを渡してあげるとうまくいきます。うまくいかない場合はコンテナ内にあるcronのログファイルを見てみましょう。

PGPASSWORD="hoge1234" pg_dump -h db5432 -Fc 【dbname】 > 【dir+dbname】.dmp

メモ:躓いたところ

  • cronがなかなか立ち上がらなかった
  • cronの実行時刻がJSTにならなかった
  • ファイルに入れたタイムスタンプがJSTにならなかった
  • 自動実行の時にpg_dumpパスワードがなくて0バイトファイルが書き出されていた
  • test環境でdevelopmentとtest両方のダンプファイルができて困惑した

おわり🏆

公開日