rsyncだけで実現する!ファイルのバックアップ手法6選 【コマンド例編】

ハードディスクのイメージ

ファイルのバックアップは、サーバー(もちろんクライアントPCでも)を運用するうえで必要不可欠なものです。Linux環境で使えるバックアップツールは様々なものがありますが、そのなかでもrsyncは汎用性が高く、広く使われています。

この記事では、実際に様々な方法でファイルをバックアップするコマンド例を紹介します。

各バックアップ手法に関する特徴やメリット・デメリットは、rsyncだけで実現する!ファイルのバックアップ手法6選 【バックアップ基礎知識編】を参照してください。

スポンサーリンク

rsyncコマンドリファレンス

この記事のコマンド例や解説では、バックアップ元やバックアップ先として以下のディレクトリ・ファイルが存在しているものとします。

バックアップ元:/test/src

バックアップ先:/test/dst

$ tree /test
/test
├── dst
└── src
    ├── image.png
    ├── script.sh
    └── text

書式

rsync [オプション] 転送元パス [転送先パス]

[ ]内は省略可能です。

転送元/転送先パスには、絶対パスもしくは相対パスが使用できます。

よく使われるオプション

オプション 説明
-a アーカイブモード。なるべく転送元ディレクトリの内容を維持したままコピーする。(具体的には、ディレクトリ・シンボリックリンク・パーミッション・タイムスタンプ・所有者・グループ・特殊ファイルをそのまま保持する)
-v 実際に転送されたファイルのリストや、転送量などの統計情報を表示する
-h 表示される情報に適切な単位をつける
-n 実際にファイル転送を行わない。-v と組み合わせると、指定したコマンドでどのようにファイル転送が行われるかの統計情報のみを表示する。コマンドのテストに便利。
-z ファイルを圧縮して転送する。ネットワーク越しの転送に便利。

転送元パスの指定方法

転送元パスがディレクトリの場合、最後に /(スラッシュ)を付けるか付けないかで挙動が変わります。

 

スラッシュを付けない場合、パスに指定されたディレクトリごとコピーします。

$ rsync -a /test/src /test/dst

$ tree /test/dst
/test/dst
└── src
    ├── image.png
    ├── script.sh
    └── text

 

スラッシュを付けた場合、パスに指定されたディレクトリ配下のファイルやディレクトリをコピーします。

$ rsync -a /test/src/ /test/dst

$ tree /test/dst
/test/dst
├── image.png
├── script.sh
└── text

コマンド例

フルバックアップ+増分バックアップ(世代管理なし)

同じコマンドで実装できます。

$ rsync -avh /test/src/ /test/dst

1回目のバックアップは、転送元に存在するファイル・ディレクトリをすべて転送先へバックアップします。(=フルバックアップ)

2回目以降のバックアップは、前回のバックアップからの変更部分(変更のあったファイルと新規作成されたファイル)のみ転送されます。(=増分バックアップ)

最もお手軽なバックアップ方法ですが、バックアップデータが同じディレクトリにたまっていくこと、転送元で削除されたファイルがいつまでも転送先に残り続けることから、バックアップディレクトリが多少ごちゃつきます。また、世代管理はできないので、増分バックアップで世代管理をしたい場合は、増分バックアップ(世代管理あり)がおすすめです。

ミラーリング

$ rsync -avh --delete /test/src/ /test/dst

–delete オプションを付けることで、転送元にないファイルは転送先からも削除されます。

これにより、転送先は常にバックアップ時点での転送元の状態を反映するようになります。(=ミラーリング)もちろん、前回のバックアップから変更がないファイルは転送されません。

バックアップの世代管理をする必要がない場合はこの手法が最も適していると思います。

逆増分バックアップ

rsync -avh --delete --backup --backup-dir="../backup-$(date +%Y%m%d-%H%M%S)" /test/src/ /test/dst/backup-latest

–delete オプションに加えて –backup オプションを付けることで、–delete によって削除されるファイルをバックアップディレクトリに退避します。ミラーリング+ミラーリングで消えるファイルのバックアップ と考えるとわかりやすいかと思います。

バックアップディレクトリの名前は、–backup-dir で指定することができます。コマンド例では、バックアップ時刻のタイムスタンプをディレクトリ名にするように設定しています。

バックアップディレクトリを転送先ディレクトリよりも1つ上の階層に置いているのがミソです。(同じ階層に置くと面倒なことになります。なぜ面倒になるのかは実際に試してみるのがわかりやすいと思います。)

 

具体的には、以下のような感じでバックアップデータがたまっていきます。きっちりと世代管理ができていることがわかります。

$ tree /test/dst
/test/dst
├── backup-20181206-040000
│   └── #2018年12月6日のミラーリングによって削除されたデータ
├── backup-20181207-040000
│   └── #2018年12月7日のミラーリングによって削除されたデータ
└── backup-latest
    └── #最新のバックアップ

差分バックアップ

#初回のバックアップ(フルバックアップ)
$ rsync -avh /test/src/ /test/dst/backup-base

#2回目以降のバックアップ(差分バックアップ)
rsync -avh --compare-dest=../backup-base /test/src/ "/test/dst/backup-$(date +%Y%m%d-%H%M%S)"

–compare-dest オプションで、既存のバックアップのあるディレクトリを指定すると、そのディレクトリと転送元の差分をバックアップすることができます。

コマンド例では、転送先ディレクトリの名前をバックアップ時刻のタイムスタンプにしています。これにより、差分バックアップで世代管理ができます。

–compare-dest オプションにおける相対パスの取り扱い

–compare-dest –link-dest –copy-dest オプションで相対パスを指定する場合、カレントディレクトリからではなく、転送先に指定したパスからの相対パスと解釈されます
※2020/5/22追記。コメントでのご指摘ありがとうございました。 

 

具体的には、以下のような感じでバックアップデータがたまっていきます。

$ tree /test/dst
/test/dst
├── backup-20181206-040000
│   └── #初回~12月6日の差分
├── backup-20181207-040000
│   └── #初回~12月7日の差分
└── backup-base
    └── #初回のフルバックアップ

実際に差分バックアップをする場合、定期的にフルバックアップをとり直すことが多いと思うので、スクリプトで自動化するにはもう一捻りする必要がありますが…

差分バックアップ(ハードリンク)

#初回のバックアップ(フルバックアップ)
$ rsync -avh /test/src/ /test/dst/backup-base

#2回目以降のバックアップ(差分バックアップ)
rsync -avh --link-dest=../backup-base /test/src/ "/test/dst/backup-$(date +%Y%m%d-%H%M%S)"

–compare-dest の代わりに –link-dest を使うと、2回目以降のバックアップディレクトリには、–link-dest で指定されたディレクトリと転送元の差分がコピーされるほか、–link-dest で指定されたディレクトリ内の変更がなかったファイルへのハードリンクが張られます。

つまり、見た目上は毎回フルバックアップをとっているように見えます。ただし、既存のファイルはハードリンクを張るだけなので、ファイル転送やディスク消費が発生するのは差分のファイルのみになります。

任意の時点のバックアップをすぐにリストアすることができるという点で、優れたバックアップ方法ですが、増分バックアップ(世代管理あり)がこれのほぼ上位互換なので、どうしても差分バックアップしたい場合くらいしか利用シーンが思いつきません。

 

具体的には、以下のような感じでバックアップデータがたまっていきます。

$ tree /test/dst
/test/dst
├── backup-20181206-040000
│   └── #12月6日時点のバックアップ
├── backup-20181207-040000
│   └── #12月7日時点のバックアップ
└── backup-base
    └── #初回のフルバックアップ

増分バックアップ(世代管理あり)

差分バックアップ(ハードリンク)の応用です。

–link-dest が常に1つ前のバックアップを指すようにスクリプトを組んでやると、世代管理ありの増分バックアップを実装できます。

個人的には、世代管理をするならこのバックアップ手法がいちばん汎用性があると思います。

#! /bin/bash

BASEDIR="/test/dst" #バックアップ先の親ディレクトリ
LATESTBKUP=$(ls $BASEDIR | grep backup- | tail -n 1) #直近のバックアップのディレクトリ名

rsync -avh --link-dest="$BASEDIR/$LATESTBKUP" /test/src/ "/test/dst/backup-$(date +%Y%m%d-%H%M%S)"

直近のバックアップは、バックアップ先の親ディレクトリをlsで表示したときの末尾を取得することで指定できます。(コード例4行目)

 

具体的には、以下のような感じでバックアップデータがたまっていきます。

$ tree /test/dst
/test/dst
├── backup-20181205-040000
│   └── #12月5日時点のバックアップ
├── backup-20181206-040000
│   └── #12月6日時点のバックアップ
└── backup-20181207-040000
    └── #12月7日時点のバックアップ

で、結局どれを使うのがいいの?

何か他に特別な要件がなければこうなると思います。(あくまで私個人の見解です)

スポンサーリンク

あわせて読みたい

6件のフィードバック

  1. omote より:

    ちょっと応用させて貰いました
    tcsh向けです

    #!/bin/sh

    BASE=/NAS01/
    LATEST=$(ls “$BASE” | grep backup_ | tail -n 1)
    EARLIEST=$(ls “$BASE” | grep backup_ | head -n 1)

    /usr/local/bin/rsync -azvh –link-dest=”$BASE/$LATEST” root@192.168.xxx.xxx:/NAS01/
    “/NAS01/backup_$(date +%Y%m%d-%H%M%S)”
    #/bin/rm -rf “$BASE/$EARLIEST”

    touch “/NAS01/backup_$(date +%Y%m%d)”*

    rmのコメント外すとrsync実行後に一番古いフォルダを消します
    touchはコピーしたフォルダの日付がなぜか飛ぶので最後に整えてます

  2. foobar より:

    増分バックアップについてなのですが、過去の世代を削除しても問題はないのでしょうか?
    たとえば backup-20210411 (初めて取ったもの) 、backup-20210412(増分)~backup-20210505(増分)と取っていって、4月分のバックアップはもう不要として、 rm -rf /test/dst/backup-202104?? などとすると、backup-202105xx にどんな影響が出るんでしょうか?

    • Admin - hackers-high.com より:

      この記事の増分バックアップ(世代管理あり)のことを指しているとすると、過去の世代を削除しても、削除したバックアップ(世代)以外の世代には影響がありません。
      ハードリンクの仕組み上、ファイルに対する参照のカウントが0にならない限りファイルが削除されないためです。(過去の世代を削除しても、それ以外の世代に同一のファイルを指すハードリンクがあれば、そのファイルは削除されません)
      ※上記説明は簡略化したもので、厳密には正しくないです。ハードリンクの仕組みを調べるとなぜファイルが削除されないのか正確に分かるかと思います。

  3. hogefuga より:

    先ほどコメントしたものです。
    本ページでは、link-destオプションで絶対パスを指定しているので、「dstディレクトリからの」相対パスにしなくてよいのでした。ごめんなさい!!
    「dstディレクトリからの」相対パスにしなくてはならないのはlink-destオプションで相対パスを使いたいときのみでした。

    • Admin - hackers-high.com より:

      なるほど、そんな仕様があったのですね…
      今回の例では大丈夫でしたが、追記させていただきます。
      ありがとうございます。

  4. hogefuga より:

    最後の増分バックアップのとこ、–link-dest=”$BASEDIR/$LATESTBKUP” じゃダメだと思います。

    https://stackoverflow.com/questions/21298179/disk-usage-issue-with-rsync-and-link-dest
    「man rsync」で出る説明だとこのオプションについて「If DIR is a relative path, it is relative to the destination directory. 」と書かれているそうなので、dstディレクトリからの相対パスになるようにしなくてはいけません。

    なのでこの場合、以下のようになります。
    rsync -avh –link-dest=”../$LATESTBKUP” /test/src/ “$BASEDIR/backup-$(date +%Y%m%d-%H%M%S)”

omote へ返信する コメントをキャンセル

質問・感想などお気軽にどうぞ。
*が付いている項目は入力必須です。メールアドレス以外の項目が公開されます。
スパム防止のため、コメント反映まで少々時間がかかります。