tarとrsyncを正確に使う
一言でいうと
tarは時点を保存するツールで、rsyncは状態を揃えるツールです。バックアップ設計では、2つは競合ではなく役割分担です。
なぜ必要なのか
「バックアップはtarでやりますか、rsyncでやりますか」という質問に、決まった答えはありません。世代ごとのアーカイブが必要ならtar、最新状態のコピーが必要ならrsyncです。そして実務の構成の大半は、両方を使います。
どう動くのか
tar
tar -czf /backup/etc-$(date +%F).tar.gz --acls --xattrs --selinux --numeric-owner -C / etc
tar -tzf /backup/etc-2026-08-20.tar.gz | head
tar -xzf /backup/etc-2026-08-20.tar.gz -C /restore/
オプションの正確な意味です。
-c(作成)、-x(展開)、-t(一覧)、-f(ファイル)が基本の組み合わせです。- 圧縮は
-z(gzip)、-j(bzip2)、-J(xz)、--zstdです。 -Cは作業の前にディレクトリを変更します。 絶対パスをアーカイブに入れないために必ず使います。tar -czf x.tgz /etcはアーカイブの中に/etc/...を入れてしまい、復元するときにパスを選ぶ自由を奪います。-p(権限の保存)と--numeric-ownerは、復元時に権限と所有者を正確に再現します。--acls、--xattrs、--selinuxは、それぞれACL、拡張属性、SELinuxコンテキストを含めます。SELinuxを使うシステムで、これらのオプションなしに復元するとサービスが起動しません。--one-file-systemは、別のファイルシステムへ踏み込みません。マウントされたネットワークストレージまで巻き込む事故を防ぎます。--listed-incremental=<스냅샷파일>は増分バックアップを管理します(プレースホルダーはスナップショットファイルです)。スナップショットファイルが状態を保持しているので、そのファイルも一緒に保管する必要があります。--strip-components=Nは、復元時に先頭のパス要素を取り除きます。
復元時は、パスを必ず確認してください。 -C /でそのまま展開すると、現在のシステム設定を上書きします。安全な手順は、一時的なパスに展開して内容を確認してから、必要なファイルだけを移すことです。
mkdir -p /restore/etc-check
tar -xzf /backup/etc-2026-08-20.tar.gz -C /restore/etc-check
diff -r /restore/etc-check/etc/nginx /etc/nginx | head -40
GNU tarとBSD tar(bsdtar)は、オプションの扱いや一部の動作が異なります。macOSで作ったアーカイブをLinuxで展開するときに、拡張属性に関するファイルが一緒に出てくる問題が代表的です。バックアップスクリプトは、実際の本番ディストリビューションで検証する必要があります。
rsync
rsync -aHAX --numeric-ids --delete --dry-run /srv/data/ backup@10.0.9.2:/backup/prod/data/
-aは-rlptgoDと同じです。ACL(-A)、拡張属性(-X)、ハードリンク(-H)は含まれません。--numeric-idsは、名前の代わりに数値のUID/GIDを使います。別のシステムに復元するときに、所有者が意図しない名前へマッピングされるのを防ぎます。-i(itemize)は、どんな変更が起きるかを1行ずつ表示します。-nと一緒に使うのが習慣になっているべきです。--bwlimitとionice -c 3 nice -n 19で、本番への負荷を下げます。
世代バックアップは、ハードリンクで安く作れます。
rsync -aHAX --numeric-ids --delete --link-dest=/backup/prod/daily.1 /srv/data/ /backup/prod/daily.0/
各世代はフルのスナップショットのように見えますが、ディスクを占めるのは変更分だけです。
2つのツールの役割分担
| 必要なこと | ツール |
|---|---|
| 特定時点のアーカイブファイル1つ | tar |
| オフサイトへ移す単一のオブジェクト | tar(+圧縮、暗号化) |
| 最新状態のコピーの維持 | rsync |
| 世代ごとのスナップショットを安く | rsync --link-dest |
| 帯域幅を節約したリモート同期 | rsync(デルタ転送) |
現場での姿
--deleteによる事故です。元のデータが空だったり、マウントが外れた状態で実行されると、コピー先のデータをすべて消します。実務で実際に繰り返される事故です。ガードが必須です。
世代バックアップを、ハードリンクを知らないツールでコピーして、容量が3倍になる事故もあります。-Hは-aに含まれません。
転送の途中でずれないようにする
tarとrsyncは単純に見えますが、大容量のデータを移すときに、静かにずれてしまう箇所があります。
変更中のファイルをそのまま保存すると壊れます。 tarは、読み取りの途中でファイルが変わるとfile changed as we read itという警告を出し、そのファイルだけが壊れた状態のまま先へ進みます。サービスを止められないなら、スナップショット(LVM、ファイルシステム、クラウドボリューム)を取って、それを保存します。
ハードリンクとスパースファイルを保存します。 オプションなしに移すと、ハードリンクがそれぞれ別のコピーになって容量が何倍にもなり、スパースファイルは0で埋められて膨れ上がります。
tar --numeric-owner --acls --xattrs --sparse -cf - /srv | zstd -T0 > srv.tar.zst
rsync -aHAX --sparse --numeric-ids /srv/ backup:/srv/
-aだけでは、ハードリンク(H)・ACL(A)・拡張属性(X)は引き継がれません。SELinuxのラベルは-Xに含まれています。
途中で切れても再開できるようにします。 --partial --append-verifyを指定すると、再開するときに最初から受信し直しません。大きなファイル1つを何日もかけて移すときに、差が大きく出ます。
末尾のスラッシュの有無で結果が変わります。 rsync -a /src/ /dst/は中身を移し、rsync -a /src /dst/は/dst/srcを作ります。スクリプトでは、この1文字のせいでパスが1階層深くなる事故が繰り返されます。
削除するときは、先に目で確認します。 --deleteは、コピー先にだけあるものを削除します。コピー元のパスが間違っていると、コピー先をまるごと空にしてしまいます。
rsync -aHAX --delete --dry-run --itemize-changes /src/ /dst/ | head -50
検証は別のステップです。 rsyncは転送中にチェックサムを使いますが、あとでファイルが傷んだかどうかは教えてくれません。一覧とハッシュを一緒に残しておけば、数か月後にも確認できます。
find /srv -type f -print0 | sort -z | xargs -0 sha256sum > manifest.sha256
sha256sum -c manifest.sha256 --quiet
次のラボですること
tarでフル・増分・除外・分割を扱い、rsyncでdry-run・ガード・世代バックアップ・負荷制御を扱います。どちらのラボも、最後に結果を検証します。