gem backupを使ってMySQLとかファイルとかをバックアップ

インフラ hironemuhironemu

会社で使っているRedmineやGitやホームページのバックアップの自動化をしなきゃしなきゃと思いつつ、まる1年が経ちまして。

ようやく重い腰を上げて設定してみました。

今回は、backup というgemを使ったバックアップの設定手順をここにまとめます。

gem backupで出来ることは下記の通りです。(他にも色々あります)

  • MySQLやファイルを対象としたバックアップに対応している
  • バックアップ先にS3等を選択できる
  • ローテーション設定も可能
  • バックアップ処理完了後にメール(やTwitterなど)で通知可能
  • cronで定期的に実行させる(これはbackupの機能じゃないけど)

 

ちなみに、今回はrvm(system wide)がインストールされている環境を前提とした、インストール&設定方法となります。

Backup用のgemsetの作成とか

# rvm gemset create backup
# rvm use 1.9.3@backup

また、今回S3にバックアップを保存するのですが、その時fogというgemを使います。そこで、以下のライブラリが必要となったのでインストールしました。

# yum install libxml2-devel libxslt-devel

必要となるgemのインストール

# gem install backup --no-ri --no-rdoc
# gem install fog -v 1.4.0 --no-ri --no-rdoc
# gem install mail -v '~> 2.4.0' --no-ri --no-rdoc

※ fogは1.4.0でないと動かないのでバージョンを指定してインストール。あ、もしかしたら’~> 1.4.0’としてもいいかも。

バックアップ用の設定ファイルの記述

今回、/root/backup/redmine_backup.rbとして作成。

# encoding: utf-8

##
#データベースのバックアップ
# $ backup perform -t redmine_db_backup [-c <path_to_configuration_file>]
Backup::Model.new(:redmine_db_backup, 'Description for redmin db backup') do
  ##
  # Split [Splitter]
  #
  # Split the backup file in to chunks of 250 megabytes
  # if the backup file size exceeds 250 megabytes
  #
  split_into_chunks_of 250

  # ファイルやフォルダのバックアップを行う場合
  # archive :git_repositories do |archive|
  #  archive.add '/home/git/repositories'
  # end

  ##
  # MySQL [Database]
  #
  database MySQL do |db|
    # To dump all databases, set `db.name = :all` (or leave blank)
    db.name               = "redmine"
    db.username           = "xxxxxx"
    db.password           = "xxxxxx"
    db.host               = "localhost"
    db.port               = 3306
    db.socket             = "/var/lib/mysql/mysql.sock"
    # バイナリログの出力が有効な設定の時
    db.additional_options = ["--quick", "--single-transaction", "--flush-logs", "--master-data=2"]
    # バイナリログの出力をしていない設定の時は下記を指定
    # db.additional_options = ["--quick", "--single-transaction"]
  end

  # S3のアクセス情報とか
  store_with S3 do |s3|
    s3.access_key_id      = 'xxxx'
    s3.secret_access_key  = 'xxxxx'
    s3.region             = 'ap-northeast-1'
    s3.bucket             = 'zealot-backup' # S3のバケット名
    s3.path               = '/redmine'      # バケット以下のディレクトリ
    s3.keep               = 3               # いくつバックアップを残すか
  end

  ##
  # Gzip [Compressor]
  # Gzipで圧縮する用に設定
  compress_with Gzip

  # メール通知
  notify_by Mail do |mail|
    mail.on_success           = true
    mail.on_warning           = true
    mail.on_failure           = true

    mail.delivery_method      = :sendmail
    mail.from                 = 'xxxx@example.com' # 送信者
    mail.to                   = 'ddd@example.com'     # 宛先
    # optional settings:
    # mail.sendmail             # the full path to the `sendmail` program
    # mail.sendmail_args        # string of arguments to to pass to `sendmail`
  end
end

cronに登録

毎朝6時5分にバックアップを取る例。rvmのパス等は環境に合わせて変更が必要。

5 6 * * * source /usr/local/rvm/environments/ruby-1.9.3-p327@backup && cd /root/backup && backup perform -t redmine_db_backup -c /root/backup/redmine_backup.rb -r /root/backup > /dev/null 2>&1
  • -t トリガー performの後ろの「-t redmine_db_backup」は設定ファイル「/root/backup/redmine_backup.rb」内の下記の名称(:redmine_db_backup)と一致させる
  • -c 設定ファイル
  • -r ルートとなるディレクトリ。ここで指定したディレクトリ以下にlog, data, .tmp, .cache等のディレクトリが作られる。「data」については後で説明します。
Backup::Model.new(:redmine_db_backup, 'Description for redmin db backup') do

実行してみる

上記の内容で実行するとS3のバケットに「/redmine/redmine_db_backup/2012.12.07.10.37.27」というディレクトリが作成され、その中にredmine_db_backup.tarというファイルができています。このファイルはsplit_into_chunks_ofで指定した250MBを超えた場合、分割して保存されます。それは、このあと説明します。

また、日時のディレクトリ「2012.12.07.10.37.27」がローテーションの単位となり、keep = 3と設定した場合、このディレクトリが3つ分保存されることとなります。

ちなみに、どうやってS3に3つのファイルがあるか判断しているかというと、S3にアクセスしてディレクトリ一覧を見ているわけではなく、ローカルのyamlファイルにどのファイルを上げたかを記録しておき、そのファイルを見てローテーションの制御を行なっているみたいです。今回の例では、ローカルの以下のファイルに記述されています。

/root/backup/data/redmine_db_backup/S3.yml

---
- !ruby/object:Backup::Package
  chunk_suffixes: []

  extension: tar
  time: 2012.12.05.06.05.04
  trigger: redmine_db_backup
  version: 3.0.27
- !ruby/object:Backup::Package
  chunk_suffixes: []

  extension: tar
  time: 2012.12.06.06.05.04
  trigger: redmine_db_backup
  version: 3.0.27
- !ruby/object:Backup::Package
  chunk_suffixes: []

  extension: tar
  time: 2012.12.07.10.37.27
  trigger: redmine_db_backup
  version: 3.0.27

というわけで、このファイルも意外と重要な役割をしています。なので、設定ファイルとこのファイルもバックアップしておくのがいいかなと思われます。

バックアップしたファイルが分割された場合

バックアップするファイルのサイズがsplit_into_chunks_ofで指定したサイズを超えた場合、〜.aa, 〜abみたいに分割してアップロードされます。

これを、くっつけるには以下のようにcatで結合するだけ。

下記の2つのファイルに分割された場合

  • git_repositories_backup.tar-aa
  • git_repositories_backup.tar-ab

次のようにして結合します。

# cat git_repositories_backup.tar-aa git_repositories_backup.tar-ab > test.tar

詳しくは下記参照。

https://github.com/meskyanichi/backup/wiki/Splitter

まとめ

RVMとか使ってるので説明がややこしくなってるとこもありますけど、非常に簡単に使えます。バックアップのスクリプトって毎回同じ事を書いていた気がするけど、これを使うと設定のみでどれをバックアップするか、どこに通知するか等やってくれるので非常に助かります。特にエラーの時の対応とかログの出力とか自分でスクリプト書くとなると意外と面倒ですし。

ちょっと残念なのは、コールバックする仕組みがないっぽいところですね。例えばS3のエラーが発生した時(とか成功した時)にコールバックできたりすると、嬉しかったりします。(例えば、MySQLのバイナリログをバックアップした時、ちゃんとS3に上がった時だけpurgeを実行させるとかしたかった。)とは言え、よくあるバックアップのパターンではまったく困らないと思います。バックアップ面倒だなーと思ってる人は是非一度ためしてみるといいかも知れません。

Tags: