Ruby
Rails
MySQL

Mysqlバックアップrakeタスクを作ってwheneverで回すまで

More than 5 years have passed since last update.


mysqlのバックアップ用rakeタスクを作成する

ここを参考にしながら、mysqlデータベースをaws s3にバックアップを行なうためのrakeタスクを書いた。そしてそれをwheneverで定期的に実行するようにしてデータベースのバックアップ体制を取りました。ここのスクリプトでは、dotenvaws-sdkに依存しています。dotenvを使用している部分はよしなに環境変数を使用するように変更すると良いと思います。

Railsでデータベースのバックアップを取るためのgemとしてbackupっていうgemもあるのですが、設定が色々と面倒くさそうだったので、ミニマムに自分で書いた方が早そうだと思って自分でスクリプト書く次第となりました。

とりあえずで書いたので、DRYになってないのでリファクタリング掛けたい所。


lib/tasks/backup.rb

require 'dotenv/tasks'

namespace :backup do

desc "nightly backup"
task :nightly => :dotenv do
timestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
backup_file = "tmp/backups/#{timestamp}_dump.sql.gz"
`mkdir -p tmp/backups`
`mysqldump -u #{ENV['DB_USERNAME']} -p#{ENV['DB_PASSWORD']} #{ENV['DB_NAME']} | gzip -c > #{backup_file}`

send_to_s3_nightly backup_file
end

desc "weekly backup"
task :weekly => :dotenv do
timestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
backup_file = "tmp/backups/#{timestamp}_dump.sql.gz"
`mkdir -p tmp/backups`
`mysqldump -u #{ENV['DB_USERNAME']} -p#{ENV['DB_PASSWORD']} #{ENV['DB_NAME']} | gzip -c > #{backup_file}`

send_to_s3_weekly backup_file
delete_olds
end

def delete_olds(num = 10)
bucket = get_bucket
bucket.objects.with_prefix("backups/nightly/").each do |backup|
datestr = backup.key.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}/)[0]
date = DateTime.strptime(datestr,"%Y-%m-%d_%H-%M-%S")
if (Date.today - num).to_datetime > date
backup.delete
end
end

bucket.objects.with_prefix("backups/weekly/").each do |backup|
datestr = backup.key.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}/)[0]
date = DateTime.strptime(datestr,"%Y-%m-%d_%H-%M-%S")
if (Date.today - num * 7).to_datetime > date
backup.delete
end
end
end

def send_to_s3_nightly(file_path)
bucket = get_bucket
file_name = File.basename(file_path)
bucket.objects["backups/nightly/#{file_name}"].write(File.open("#{file_path}"))
end

def send_to_s3_weekly(file_path)
bucket = get_bucket
file_name = File.basename(file_path)
bucket.objects["backups/weekly/#{file_name}"].write(File.open("#{file_path}"))
end

def get_bucket
s3 = AWS::S3.new(
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
s3_endpoint: ENV['S3_HOST_NAME']
)
bucket = s3.buckets[ENV['S3_BUCKET_NAME']]
bucket = s3.buckets.create(ENV['S3_BUCKET_NAME']) unless bucket.exists?
bucket
end
end



wheneverで定期的に実行する

先ほど書いたrakeタスクをwheneverで毎日、毎週走らせます。こちらを参考に導入しましたが、導入が簡単で良いですね。

まずは、wheneverをGemfileに追加


Gemfile

+ gem 'whenever', :require => false


wheneverの設定ファイルを生成するコマンドが付いてくるので、実行します。

cd path/to/project_dir/

wheneverize .

先ほど生成された設定ファイルconfig/schedule.rbに設定を書いて行きます。capistranoと連携させるために、roleを記述しています。


config/schedule.rb

# 出力先のログファイルの指定

set :output, 'log/crontab.log'
# ジョブの実行環境の指定
set :environment, :production

# 毎日 am4:30のスケジューリング
every 1.day, :at => '4:30 am', :roles => [:db] do
rake "backup:nightly"
end

# 日曜日のpm12時にスケジューリング
every :monday, :at => '4am', :roles => [:db] do
rake "backup:weekly"
end



capistrano v3でデプロイ時にwheneverを設定するようにする


Capfile

+require "whenever/capistrano"

+SSHKit.config.command_map[:whenever] = "bundle exec whenever"


config/deploy.rb

set :whenever_environment, "#{fetch(:stage)}" #wheneverでの環境指定に必要

set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" } #cronjobのユニークを保つために必要

これで、デプロイの設定は終了。あとは

bundle exec cap production deploy

すれば、自動でwheneverの設定を反映させてくれます。