- お知らせ -
  • 当wikiのプログラムコードの表示を直してみました(ついでに長い行があると全体が下にぶっ飛ぶのも修正)。不具合があればBBSまでご連絡下さい。

Ruby/Ruby on Rails/デプロイ/Capistrano

はじめに Edit

Rails環境でDB(MySQL)のバックアップとリストアをCapistranoから自動化する方法を書いてみます。

Capistrano v2.5.5、クライアントはWindows XP、サーバー側はUbuntu 8.04で確認しました。

記述例 Edit

前提条件 Edit

  • MySQLを使っている
  • mysqldumpが使える
  • capistranoがそもそもちゃんと動いている
  • config/database.ymlの設定でDBにアクセスできる
  • アプリ&DBサーバーが1台の時しかテストしてない件
  • capistrano-ext(参考)使ってstaging鯖とproduction鯖とどちら向けに実行してもうまく行くようになってるハズ(ドメイン名でバックアップファイル名生成)
  • リモートの”(プロジェクト)/shared/backups/”以下にどんどんバックアップする
  • ローカルの”(プロジェクト)/../backups/”以下にも同じのをどんどんバックアップする

上記のようなのを想定してます…。

コード Edit

例えば以下のようにconfig/deploy.rbに追記で書いてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
before "deploy:migrate", "backup:mysql"

# バックアップ用
namespace :backup do
  desc "Backup remote production DB with mysqldump"
  task :mysql, :roles => :db, :only => { :primary => true } do
    require 'yaml'

    filename = "#{application}.#{domain.gsub(".", "_")}.#{Time.now.strftime("%Y-%m-%d_%H-%M-%S")}.sql.bz2"
    file = "#{shared_path}/backups/#{filename}"
    on_rollback { delete file }

    # DBの設定読み込み
    db = YAML::load(ERB.new(IO.read(File.join(File.dirname(__FILE__), 'database.yml'))).result)['production']

    # フォルダ作成
    run "mkdir -p #{shared_path}/backups"
    # MYSQL dump
    run "mysqldump -u #{db['username']} --password=#{db['password']} #{db['database']} | bzip2 -c > #{file}"  do |ch, stream, data|
      puts data
    end
    # 手元に持ってくる
    backup_dir = File.dirname(__FILE__) + "/../../backups/"
    FileUtils.mkdir_p backup_dir
    get file, "#{backup_dir}/#{filename}"
  end

  desc "Restore DB by mysqldumped mysql file(-S sql=dumpled_filename)"
  task :restore_mysql, :roles => :db do
    filename = sql
    unless sql   # (実は意味なし)そもそも-S sql=〜〜で書かないとsqlないと言われてエラーになる
      abort "error: specified -S=dumped_filename"
    end

    unless Capistrano::CLI.ui.agree("Confirm replace and restore DB data? (y/n)")
      abort "Restore Canceled..."
    end

    file = "#{filename}"
    filename_only = File::basename(filename)
    # tmp/~~~~.sql.bz2
    out_file = "/tmp/#{filename_only}"
    # tmp/~~~~.sql
    out_sql_file = File.join(File::dirname(out_file), File::basename(out_file, ".*"))
    # すでにファイルがあると解凍できないので消しとく
    run "rm #{out_sql_file}; true"
    #on_rollback { delete out_file; delete out_sql_file }

    # DBの設定読み込み
    db = YAML::load(ERB.new(IO.read(File.join(File.dirname(__FILE__), 'database.yml'))).result)['production']
    # bz2転送
    upload file, out_file
    # 解凍
    run "bunzip2 #{out_file}"
    # リストア
    run "mysql #{db['database']} -u #{db_user} -p#{db['password']} < #{out_sql_file}"
    run "rm #{out_sql_file}; true"
  end
end

このデプロイスクリプトの使い方 Edit

上記のように書いてみた時の使い方

自動バックアップ Edit

cap deploy:cold コマンドでdb:migrate前に自動でDBをバックアップできます。

cap deploy:coldするとrake db:migrateが走りますが、
migrate前に自動でmysqldumpしてbz2で固めてshared/backupsにアプリ名、ドメイン名、日時でファイル名をつけてDBのバックアップを置いてくれます。
また、プロジェクトのディレクトリ上の backups/ディレクトリにも同じファイルをリモートからコピーしてきます。

つまり、

  • リモートのDBサーバーの”shared/backups/(アプリ名).(ドメイン名).(日付時間).sql.bz2”
    のファイル名でDBがバックアップされる
  • クライアントの”(プロジェクト)/../backups/(アプリ名).(ドメイン名).(日付時間).sql.bz2”
    にもバックカップされる

ということになります。

手動バックアップ Edit

手動でバックアップする場合は、

cap backup:mysql

すると、上記の自動バックアップで書いた事をその場で手動で実行できます。
(もちろん、rake db:migrateは実行されません)

データのリストア Edit

バックアップしたデータをリストアもできます。

cap backup:restore_mysql -S=(backup:mysqlでバックアップした〜.sql.bz2のファイル名)

つまり、

cap backup:restore_mysql -S=../../backup/myapp.foo_bar_com.2009-12-17-00_01_12.sql.bz2

などのように、最後に -S=(sql.bz2ファイル名)のとともにDBのバックアップをbz2で固めたもの(上記backup:mysqlでバックアップしたもの)を指定します。

※-S=を指定しないとわかりにくいエラーがでてしまいます。

  • Sが指定されているか確認する方法があればいいのですが…。

なお、コマンド実行前には念のため、

Confirm replace and restore DB data? (y/n)

などと確認がでるので、yを押して<ENTER> を押してください。
間違った場合は、Ctrl+Cかnを押せば大丈夫です、まだ間に合います。

課題 Edit

  • config/database.ymlから読んでくるところが重複している。DRYじゃない。
  • dumpしたsqlファイルはテキストでgitに突っ込めばいいんじゃないの?とかw
    →参考:Backup your Database in Git | Viget Extend

参考URL Edit


No comment. Comments/Ruby/Ruby on Rails/デプロイ/Capistrano/MySQLのバックアップとリストア?

Name:

Front page   Edit Freeze Diff Backup Upload Copy Rename Reload   New Pages Search Recent changes   Help   RSS of recent changes
Last-modified: 2009-12-17 Thu 00:12:36 JST (1589d)