Edited at

lsyncd と rsnapshot でリアルタイム Time Machine 風バックアップを組もう

More than 1 year has passed since last update.

Apple 社の Time Machine に似た増分バックアップの仕組みに、さらにリアルタイム性を付加したバックアップシステムについて検討します。用途はホームディレクトリの世代バックアップやサーバ上の重要なデータの保全などです。

思考実験以上・運用レポート以下といったところです、長期の本運用はしていないため何か落とし穴があるかもしれません。


目指すこと

「データのリアルタイムなコピー(レプリカ)をローカルに保全」しつつ、かつそれの「1時間ごとの世代バックアップを作成」することを目指します。

典型的には、ローカルマシンにマウントした外付けディスクや NAS をバックアップ先に指定することになるでしょう。別マシンへ直接バックアップする方法についてものちほど検討しますが、ひとまずローカルディスクに保存し、そのデータをさらに他のサーバへ定期的にコピーする運用を考えます。

全体の構成図・概略


  • 変更のあったファイルを数秒の遅れで別ディスクに保全する


    • 変更のあったファイルの増分のみ保存し容量を節約する

    • 容量の大きいファイルや特定のディレクトリを除外する

    • 古いバックアップファイルを自動的に消し込む



  • Time Machine 風の世代バックアップを行う


    • 世代の間隔や数を自由に設計する

    • 任意の長期間で保存する(設定上の上限なし)



これらの機能を lsyncdrsnapshot という2つのソフトウェアを組み合わせて実現します。


lsyncd とは

lsyncd (Live Syncing Daemon) は、指定したディレクトリ以下に含まれるファイルを inotify (Linux) や kqueue (BSD) を使ってリアルタイムにウォッチし、更新されたファイルがあれば即時に転送を開始するツール です。分単位のダウンタイムすら許容できない状況に威力を発揮する、攻めのツールと言えます。

デーモンとして常駐し、裏では rsync を使ってファイルを同期します。データを他のマシンへ転送したり、Amazon S3 に上げることなども可能です。ただし、今回はローカルマシン上のファイルコピーに使います。

なお、動作が若干不安定という話もあるようですから、定期的に再起動したり動作をチェックするような仕組みを導入することを検討するとよさそうです。


rsnapshot とは

rsnapshot は、macOS の Time Machine に似た設計思想に基づいた増分バックアップシステムを実現するためのスクリプトです。

Time Machine の設計とは、まず初回実行時にフルバックアップを取得し、以降は1時間毎に前回から変更されたファイルのみバックアップを取り、30日を過ぎたバックアップは週ごとに1つに間引いて、ディスクの容量がある限りデータを保存する方式です。

スクリプトは Perl で書かれており、mkdir/mv 等の基本的なコマンドと rsync を組み合わせて cron で実行する、シンプルな動作が特長です。バックアップされたそれぞれのファイルはハードリンクとして存在し、変更があったファイルのみ実ファイルとして保持されます。


rdiff-backup との比較

同じような目的のソフトウェアに rdiff-backup がありますが、以下の欠点のため今回は採用しません。


  • rsync コマンドを直接呼び出さないので、細かい動作の指定ができない

  • 過去のデータを取り出すのにコマンドを実行する必要がある

  • 古いデータを消し込むタスクを別途仕込む必要がある

対して rsnapshot は Unix コマンドを組み合わせて実現しているのでシンプルで分かりやすい作りになっています。問題が起きても調査が容易な点は、安定した長期運用を目指す際に大いにプラスとなります。


環境を構築する


lsyncd をインストールする

yum や brew で入ります。

yum install lsyncd

デーモンとして動作するので、今回は root 権限で起動し、設定ファイルはグローバルのものを使います。


rsnapshot をインストールする

同じく yum や brew で入ります。perl が必要です。

yum install rsnapshot

cron からコマンドを呼び出す形で使用します。今回は各ファイルのオーナーなどの情報を保持したいので root 権限で起動し、設定ファイルはグローバルのものを使います。


監視ファイルの上限を緩和する

Linux では上限数がそれほど多くないので、あらかじめ上限を緩和しておくとよいと思います。/etc/sysctl.conf に書き込むのも忘れずに。

sysctl -w fs.inotify.max_user_watches=65536

他の OS の対応方法は見つけられませんでした。FreeBSD の kqueue(2) まわりを調べる必要があるかもしれません。情報をお待ちしています。

OS が同時に開けるファイル数もチェックしたほうがよいでしょう。linux なら fs.file-max、macOS なら kern.maxfileskern.maxfilesperprocようです


システムの構成を設計する

ここでは、ローカルマシンのディレクトリ /app/myproject 以下を、同じくローカルマシンの /mnt/rsnapshot 以下にバックアップすることにしましょう。/mnt は別のファイルシステム(外付け HDD、NAS 等)をマウントする想定ですが、もちろん同一ディスク上でも(冗長性は下がりますが)運用やテストは可能です。

ローカルの構成図


確保すべき空き容量

初回バックアップ時には、/app/myproject2倍の容量が必要です。これは lsyncd によるリアルタイムバックアップ用の領域 (a) と、rsnapshot の実ファイル格納用の領域 (b) がそれぞれ別に必要だからです。


  • (a) /mnt/rsnapshot/current/

  • (b) /mnt/rsnapshot/.sync/

さらに日々の増分の保持に必要となるディスク容量は、どう運用したいかによって大きく変わります。


  • どの程度頻繁にファイルを更新するか(また、それらのファイル容量)

  • データを何ヶ月・何年くらい保持したいか

もしあまりデータを更新しないのであれば 1.5 倍程度あればひとまず試すには充分かと思います。実運用される場合は、ディスクが満杯にならないよう要監視です。

まとめると、もし /app/myproject が 10GB あるなら、/mnt は少なくとも 30GB は確保したいところです。長期運用するなら大ざっぱに 100GB くらいでしょうか。


lsyncd を設定する

rsnapshot のバックアップ先にデータを同期することになるので、まず転送先にディレクトリを作ります。

mkdir -p /mnt/rsnapshot/current/app/myproject/

設定ファイルはデフォルトで /etc/lsyncd.conf です。ちなみに Lua 互換の形式です。

vi /etc/lsyncd.conf

ここでは root で実行することを前提としています。


lsyncd.conf

settings {

logfile = "/var/log/lsyncd.log",
statusFile = "/tmp/lsyncd.status",
maxDelays = 1,
}

sync {
default.rsync,
source = "/app/myproject/",
target = "/mnt/rsnapshot/current/app/myproject/",
delete = true,
rsync = {
archive = true,
hard_links = true,
}
}


sync セクションは複数書くことできます。詳しいオプションはマニュアルをどうぞ。


削除の扱い

もし手元で削除したファイルも残しておきたいなら delete = false を指定します。より安全ですが、たまたま間違えて手元にコピーした巨大なファイルが残り続けるかもしれません。基本的には true でよいでしょう。実運用する時は delete = running を指定することを検討してみて下さい


起動する

systemctl start lsyncd

手元で動作をみたい場合は settings セクションに nodaemon = true を指定するか、あるいは次にように実行します。

lsyncd -nodaemon /etc/lsyncd.conf   


rsnapshot を設定する

設定ファイルはデフォルトで /etc/rsnapshot.conf です。brew で入れた方は /usr/local/etc/rsnapshot.conf ですが、うまく読み込んでくれない場合は都度 -c /usr/local/etc/rsnapshot.conf などと指定してください。

vi /etc/rsnapshot.conf

ここでは root で実行することを前提としています。個人のホームディレクトリ以下が対象なら一般ユーザでも動かせると思います、その場合はログファイルの場所などを調整してください。


rsnapshot.conf

config_version  1.2

snapshot_root /mnt/rsnapshot/

cmd_rsync /usr/bin/rsync
cmd_rsnapshot_diff /usr/bin/rsnapshot-diff

retain hourly 24
retain daily 7
retain weekly 4
retain monthly 12
retain yearly 10

logfile /var/log/rsnapshot.log
lockfile /var/run/rsnapshot.pid

rsync_short_args -a
rsync_long_args --delete-after --numeric-ids --relative --delete-excluded
link_dest 1
sync_first 1

backup /mnt/rsnapshot/current/app/myproject/ myproject


項目の区切りはスペースではなくタブのみ使えます。マニュアルも参照してみてください。

なお、backup はいくつでも指定できます(lsyncd.conf の sync セクションと合わせてください)。


世代を設計する

上記の設定だと、1時間毎に前回からの変更点のバックアップを取り、そのうち最古の1つを残し「その日」を代表するバックアップとすることで毎日のバックアップとし、そのうち最古の1つを残し「その週」を代表するバックアップとし…… という仕組みで、直近であるほどたくさんのバックアップを残し、最終的に1年に1つの代表データを保持することになります。

これを超えたデータは最終世代の実行時、つまり rsnapshot yearly によって消去されます。


Time Machine に合わせる例

次のようになるでしょう。個人のデータ(とくにクリエイティブ系)が対象だとこちらのほうが実用的かもしれませんね。


rsnapshot.conf

retain  hourly  24

retain daily 30
retain weekly 520 # 10年分

ただし、実際の Time Machine と違って、ディスク容量がいっぱいになる前に古いものが自動的に消えたりはしないので weekly の数は慎重に調整してください。


世代を新設する例

たとえば季節ごとに年4回保存する世代を間に挟むこともできるでしょう。なお、retain を書く順序が大切ですのでこの場合は必ず monthlyyearly の間に入れて下さい。


rsnapshot.conf

retain  seasonally  4


そして、3か月に1回 rsnapshot seasonally を実行するよう cron に仕込みます(後述)。早い話、cron で実行する間隔にマッチしていればいいわけです。


データの同期をテストする

これで cron を仕込めば稼働はしますが、まずは手作業で動作を理解するのがよいでしょう。

テスト用のフラグ -t を指定して、同期時に実際にどういったコマンドが実行されるのかチェックします。

rsnapshot -t sync

echo 75394 > /var/run/rsnapshot.pid

mkdir -m 0755 -p /mnt/rsnapshot/.sync/
rsync -a --delete-after --numeric-ids --relative \
--delete-excluded /mnt/rsnapshot/current/app/myproject/ \
/mnt/rsnapshot/.sync/myproject
touch /mnt/rsnapshot/.sync/

(注:コマンド形式で出力されますが、これとまったく同一のコマンドが発行されるわけではなく、実際には同等の動きをする Perl のコードが実行されます。つまり論理的な動きを表している、というわけです。以下同じ)。

問題なさそうなら、初回の同期を実行してみます。ついでにデバッグフラグ -v を付けましょう。全データをコピーしますから、初回はかなり時間がかかるかもしれません。

rsnapshot -v sync

無事に完了すれば /mnt/rsnapshot/.sync の中にデータがコピーされているはずです。


世代のローテートをテストする

最小単位(=設定ファイルにある複数の retain 行の一番上の世代)である hourly を実行してみます。

rsnapshot -v hourly

echo 75977 > /var/run/rsnapshot.pid

mv /mnt/rsnapshot/.sync/ /mnt/rsnapshot/hourly.0/
rm -f /var/run/rsnapshot.pid

.sync が mv され hourly.0 ディレクトリになりました。

次に、バックアップ元の /app/myproject/ の中を適当に変更してから、再度手動で実行してみます(なお rsnapshot sync した結果に変更がなければディレクトリ作成はスキップされます)。

その前に忘れず sync しましょう。

rsnapshot -v sync && rsnapshot -v hourly

出力からローテートのところだけ抜き出しました。

mv /mnt/rsnapshot/hourly.0/ /mnt/rsnapshot/hourly.1/

mv /mnt/rsnapshot/.sync/ /mnt/rsnapshot/hourly.0/

上記のステップがあと22回繰り返されて hourly.23 ディレクトリが作成されると次のような動きになります。

mv /mnt/rsnapshot/hourly.22/ /mnt/rsnapshot/hourly.23/

mv /mnt/rsnapshot/hourly.21/ /mnt/rsnapshot/hourly.22/
mv /mnt/rsnapshot/hourly.20/ /mnt/rsnapshot/hourly.21/
...
mv /mnt/rsnapshot/hourly.2/ /mnt/rsnapshot/hourly.3/
mv /mnt/rsnapshot/hourly.1/ /mnt/rsnapshot/hourly.2/
mv /mnt/rsnapshot/hourly.0/ /mnt/rsnapshot/hourly.1/
mv /mnt/rsnapshot/.sync/ /mnt/rsnapshot/hourly.0/

次の世代である daily が動作できる状況になります。synchourly が一時間に一度実行すれば充分ですから、コマンドは単に次のようになります。

rsnapshot -v daily

mv /mnt/rsnapshot/hourly.23/ /mnt/rsnapshot/daily.0/

シンプルな仕組みであることがよくわかります。実行した時点でもっとも古いものが hourly 世代の代表として daily 世代へと「引き渡され」るわけですね。


rsnapshot のタスクを登録する

上記の動きをふまえ、次のような設定を cron に仕込みます。ログの出力先などは適宜変更してください。

vi /etc/cron.d/rsnapshot


/etc/cron.d/rsnapshot

10 * * * * root /usr/bin/rsnapshot sync && /usr/bin/rsnapshot hourly >> /mnt/rsnapshot/cron.log 2>&1

15 3 * * * root /usr/bin/rsnapshot daily >> /mnt/rsnapshot/cron.log 2>&1
20 3 * * 0 root /usr/bin/rsnapshot weekly >> /mnt/rsnapshot/cron.log 2>&1
25 3 1 * * root /usr/bin/rsnapshot monthly >> /mnt/rsnapshot/cron.log 2>&1
30 3 1 1 * root /usr/bin/rsnapshot yearly >> /mnt/rsnapshot/cron.log 2>&1

Time Machine と同じ世代設計にしたい場合は、もちろん monthly や yearly の行は必要ありません。

特に日々の作業領域をバックアップする場合は、daily 以下の世代は実行する時間や曜日を注意深く設計して下さい。もっともデータの変更がなさそうな落ち着いた時間や曜日のバックアップを次の世代に引き渡すことで、たとえば日中にデスクトップに誤って作成した(そして即時コピーされてしまった)一時的で巨大なファイル等を持ち回らなくて済む確率が上がるはずです。

ついでに whenever をお使いの方のための例も置いておきます


別サーバへのバックアップについて検討する

今回の構成では、別マシン上への直接のバックアップ作成は仕組み上できません(が、のちほど検討します)。rsnapshotpull が前提のツールであるのに対しlsyncdpush が前提のツールであるため、両者の設計思想が見事にバッティングするためです。

ローカルマシン(の環境)が物理・論理問わず吹っ飛んだ時のためにリアルタイムバックアップをしたい場合がほとんどでしょうから、どのように他のマシン(ここではバックアップマシンと呼びます)へデータを転送し冗長性を確保するかが大きな課題となります。

他のマシンへデータをなるべくリアルタイムに転送するためのいくつかアイデアを挙げておきます。


定期的に別サーバへ転送する(rsync 版)

単純にバックアップデータディレクトリ /mnt/rsnapshot 以下 をなるべく短い間隔で別途 rsync を走らせて他のサーバへ転送する方法です。若干消極的で冗長ですが、シンプルで安全確実です。


/etc/cron.d/backup-rsnapshot-repository

*/3 * * * * root /usr/bin/nice -10 /usr/bin/rsync -azq --del --hard-links /mnt/rsnapshot/ you@exmaple.com:/path/to/backup/dir/


キモは --hard-links フラグの指定で、これを省くと20倍くらいの(ハードリンクではなく)実データが転送されてしまいます。反面、結果的に冗長性はすごく確保できるのでディスク障害によるデータロストにはめっぽう強くなるでしょうから、データの重要度によってはそういった運用もアリかもしれません。

同期元(ローカルマシン)上でローテートされる関係上、--del スイッチを付けておかないと整合性が取れなくなるような気がします。いずれにしてもバックアップの総容量はローカル側で調整すべきでしょうから、付けておくほうがよいと思います(未検証)。


定期的に別サーバへ転送する(lsyncd 版)

もちろん、どうせならこの転送自体も lsyncd に行わせ、ダウンタイムを短くすることも可能です。lsyncd.conf に新しい sync セクションを追加します。


lsyncd.conf

sync {

default.rsyncssh,
source = "/mnt/rsnapshot/",
host = "you@exmaple.com",
targetdir = "/path/to/backup/dir/",
delete = true,
ssh = {
identityFile = "/home/you/.ssh/id_rsa",
},
rsync = {
binary = "/usr/bin/rsync",
archive = true,
hard_links = true,
}
}

root で実行する想定なので、identityFile で一般ユーザの秘密鍵を指定しています。

ただ、個人的には安定性を考えると上記の rsync 版を採用するほうが良いようにも思います。というか、どうせならどちらも仕込んでおくのが賢い運用となりそうです。

なお、current ディレクトリを exclude ディレクティブで省かないでください。ハードリンクの関係か、データが正しくコピーされないようです。


バックアップマシンからデータを取り出す

過去の(つまり hourly.1 以降の)ファイルを参照する場合は、ふつうにアクセスすればよいので問題ありません。すべての世代ディレクトリ以下は整合性が取れているはずです(厳密には、バックアップ用の rsync/lsyncd プロセスが起動から1時間以内に完了していることが前提)。

問題は、最新のファイルを取り出したい時です。データのバックアップ転送のプロセスが完了しない限り、バックアップマシン上の最新のデータは整合性が取れていない状態にある可能性が高いと推測できます。

バックアップマシン上から最新のデータ一式を整合性を保った状態でサルベージする時には、次のような手順を踏むべきでしょう。


ローカルマシンが生きている場合


  • 転送のプロセスの起動設定をオフにする


    • rsync なら cron を停止

    • lsyncd なら設定ファイルの該当行をコメントアウトして再起動



  • 転送のプロセスが動作していないことを確認する(あるいは kill で落とす)

  • 転送のプロセスを手動で実行し、正常に完了することを確認する

  • データを取り出す

  • 転送のプロセスの起動設定をオンにする

hourly.0 から取り出します。


ローカルマシンが吹っ飛んだ場合

hourly.0 の整合性が取れている保障が得られなくなったわけですから、安全性からみると hourly.1 から取り出すことになるでしょう。


運用する


特定のファイルを対象から除外したい

例えば個々のファイルのサイズにより制限したい時は lsyncd.conf の rsync セクションに --max-size を指定します。ほかにも rsync コマンドが受け付けるものならその多くは指定できるようです。


lsyncd.conf

  rsync = {

...
_extra = {
...
"--max-size=102400000",
}
}


特定のディレクトリを対象から除外したい

lsyncd.conf の exclude セクションに指定できます。


lsyncd.conf

  exclude = {

"secrets/",
"downloads/"
}


同期 cron タスクの多重起動を防止したい

データの同期に要する時間が最小ローテート間隔(上記の設定では1時間)を上回るとタスクが多重起動しやっかいな状況に陥るので、これを防止します。

いくつか方法があると思いますが、私は timeout(1) と、daemontools に含まれる setlock を組み合わせて使っています。

15 3 * * * root /usr/bin/timeout --preserve-status --kill-after=5m 3600 /usr/local/bin/setlock -nx /var/tmp/rsnapshot_daily.lock /usr/bin/rsnapshot daily >> /mnt/rsnapshot/cron.log 2>&1

実際には、毎時の同期に常に30分以上かかるような状況で運用するのはやめたほうが安全でしょう。


バックアップが正しく取れているかどうか監視したい

Nagios で監視する例を検討します。


lsyncd

実際にファイルが転送されているかどうかを日々チェックしたいわけですが、これがなかなかやっかいです。なにしろファイルが変更されない限りはなにも転送されない(のが正しい動作)わけですから、必ず定期的に更新されるファイルの最終更新時間をチェックするほかありません。

ホームディレクトリ以下をバックアップするなら、アイデアとして次のようなファイルが使えそうです。


  • ~/.bash_history

  • ~/Desktop/.DS_Store

これらの最終更新時刻をチェックすればひとまずよさそうです。が、信頼性は低いですね。

/path/to/check_file_age -w 43200 -c 86400 /mnt/rsnapshot/current/app/myproject/something

確実性を求めるのなら、面倒ですが5分に1回くらい適当なファイルを更新するタスクを cron に仕込んで、そのファイルを監視する手が考えられます。容量をケチるために 0 バイトのファイルにしましょう。


/etc/cron.d/lsyncd-touch

*/5 * * * * you /bin/touch /app/myproject/latest


/path/to/check_file_age -w 330 -c 600 /mnt/rsnapshot/current/app/myproject/latest

その他の手としては、/mnt/rsnapshot/current/app/myproject/ 以下を find(1) を使って最近更新されたファイルがあるかどうか探す方法も考えられますが、あまりスマートではありませんね。


rsnapshot

方針としては、hourly.0 ディレクトリの作成時刻が約1時間以内であれば、rsnapshotのローテートが動いていると期待できます。

/path/to/check_file_age -w 3660 -c 7200 /mnt/rsnapshot/hourly.0


ディスクの残り容量を勘案して古いバックアップファイルを自動的に消したい

この問題は真面目に取り組むとかなり大変な気がします、簡単な解決法はないでしょう。ディスク容量を日頃からチェックし、世代の数を調整したり大きなファイルを除外するなど、地道な調整を行う必要がありそうです。次項も参考にどうぞ。


ディスクの残り容量を気にせずにバックアップしたい

AWS EC2 のインスタンス上で運用する場合に限定されますが、ひとつのアイデアとして Amazon EFS (Elastic File System) の利用が考えられます。EFS は容量無制限の NFS ディスクをマウントできるサービスです。が、私はまだ使ったことはありません(2017/01 時点で北米のリージョンでのみ提供)。

最初のバックアップ先 /mnt/rsnapshot を EFS でマウントしたパスに指定することにより耐障害性が上がることを期待できるとともに、事実上ディスク容量の残りを気にする必要が永久になくなるでしょう(その代わりに費用を気にする必要はありますが)。


lsyncd が拾いきれなかったときにリカバリしたい

lsyncd はウォッチできるファイルの最大数を超えたりファイル名が長すぎたりすると失敗したり、ちょっとナイーブです。うまく転送しきれなかった場合に備えて、別途リカバリ用の rsync タスクを定期的に走らせると少し安心度が高まるかもしれません。


/etc/cron.d/lsyncd-recovery

*/10 * * * * root /usr/bin/rsync -a --del --hard-links /app/myproject/ /mnt/rsnapshot/current/app/myproject/


転送エラーを検知するには lsyncd のログを監視する方法が考えられます。もちろん、対処療法に過ぎませんから環境や設定を見直すべきでしょう。


1分ごとに全データを残したい

真に剛の者なら1分ごとにすべてのバックアップを残したいかもしれませんね。minutely を新設し、これ1本で回します。これぞ最強の世代バックアップシステムと言えましょう。


rsnapshot.conf

retain  minutely    5259600    # 10年分!



/etc/cron.d/rsnapshot

* * * * * root /usr/bin/rsnapshot sync && /usr/bin/rsnapshot minutely  >> /mnt/rsnapshot/cron.log 2>&1


ただ、同一ディレクトリの中に最大で 500 万ディレクトリも作るとたいへんにアクセスが遅くなると思いますので、せめて1か月より古いものは hourly 以下に落としたほうがよいでしょう。

え、1分なんて無限にも等しいからせめて1秒ごとに残したい? あなたはもしや AI かなにかですか。健闘を祈ります!


その他メモ

よく知られた落とし穴ですが、rsync でディレクトリを指定する時は末尾のスラッシュの有無で意味が変わるので注意してください。慣れないうちは「必ずスラッシュをつける」に統一しておくとトラブルは少ないと思います。

新しい lsyncd は新しめの rsync を要求します。バックアップ先マシンの rsync バージョンに気をつけて下さい(サーバ用 OS のパッケージでは古い可能性があります)。


最初から他のサーバへ直接データを転送する(探求者向け)

そもそも lsyncd が直接 /mnt/rsnapshot/.sync ディレクトリ以下にデータを放り込めれば、とてもスマートです。中間データ置き場として current/ をわざわざ用意するのは容量の無駄ですからね。

なぜこれができないかというと、rsnapshot.sync ディレクトリを毎回 mv (rename) するからです。そのため、世代の数だけ実ファイルがコピーされ(そして1時間ごとに .sync へフルに再転送され)、ディスクの使用量(とネットワーク帯域)がすごいことになってしまいます。

逆に考えると、「最初の世代の最新へのコピー」だけ、うまくハードリンクをコピーするよう rsnapshot を改造してやれば実現できることになります。やっつけパッチを作ってみましたので、チャレンジャーな方はお試し下さい。

理想の構成図

rename の代わりに次のようなコマンドを実行するようになります。理論上1回しか実行されませんので(毎回が新規フルコピー)、--del 系オプションは意味が無いので付けません。

rsync -a --link-dest=../.sync/ /mnt/rsnapshot/.sync/ /mnt/rsnapshot/hourly.0/

lsyncd.conf は次のようになります。rsync+ssh でネットワーク越しに転送し、リモートの /var/rsnapshot 以下に格納することにしましょう。


lsyncd.conf

sync {

default.rsyncssh,
source = "/app/myproject/",
host = "you@example.com",
targetdir = "/var/rsnapshot/.sync/app/myproject/",
delete = true,
ssh = {
identityFile = "/home/you/.ssh/id_rsa",
},
rsync = {
binary = "/usr/bin/rsync",
archive = true,
hard_links = true,
}
}

lsyncd の実行前に、転送先のディレクトリを作成しておきます。

ssh you@example.com mkdir -p /var/rsnapshot/.sync/app/myproject

rsnapshot.conf の変更点は次の通りです。ローテート機能しか使わなくなるので、バックアップ元は適当にダミーを設定しておきます(ただし、存在しないパスだと rsnapshot が動作しません)。


rsnapshot.conf

...

backup /dev/null .

また、crontab に書いている rsnapshot sync は要らなくなりますので削除します。


/etc/cron.d/rsnapshot

10 * * * * root /usr/bin/rsnapshot hourly  >> /var/rsnapshot/cron.log 2>&1

15 3 * * * root /usr/bin/rsnapshot daily >> /var/rsnapshot/cron.log 2>&1
20 3 * * 0 root /usr/bin/rsnapshot weekly >> /var/rsnapshot/cron.log 2>&1
...

嬉しい副作用として、初期容量を元データの等倍しか必要としないシステムにアップグレードできました。ついでに ln -s .sync current しておくと多少利便性が上がるでしょう。


おわり

数秒前に更新したデータから数年前のデータまでがひとつのディレクトリ以下に格納され、通常の操作ですぐに参照できる環境というのはなかなか万能感がありますよね。

実際に運用するとなるとまだ検討と経験が必要そうではありますが、今回の構成はひとまずのスタート地点になり得るのではと思います。

それでは、よいバックアップライフを!