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

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

[ここ](http://www.alexonsager.net/blog/2013/11/29/rake-task-to-backup-mysql-to-amazon-s3/)を参考にしながら、mysqlデータベースをaws s3にバックアップを行なうためのrakeタスクを書いた。そしてそれをwheneverで定期的に実行するようにしてデータベースのバックアップ体制を取りました。ここのスクリプトでは、[dotenv](https://github.com/bkeepers/dotenv)と[aws-sdk](https://github.com/aws/aws-sdk-ruby)に依存しています。dotenvを使用している部分はよしなに環境変数を使用するように変更すると良いと思います。

Railsでデータベースのバックアップを取るためのgemとして[backup](https://github.com/meskyanichi/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で毎日、毎週走らせます。[こちら](http://morizyun.github.io/blog/whenever-gem-rails-ruby-capistrano/)を参考に導入しましたが、導入が簡単で良いですね。

まずは、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の設定を反映させてくれます。