定期バックアップと復旧

LinuxBeginner
オンラインで実践に進む

はじめに

有用なバックアップは、単にアーカイブコマンドを実行するだけでは完成しません。何が含まれているかを確認し、読み取り可能であることを検証し、必要なファイルを復旧できるようにしたうえで、無人実行の結果を追跡できる状態にする必要があります。

この実験では、マニフェストを使用して小規模なアプリケーション作業領域をバックアップし、指定したファイルを 1 つだけ復旧します。その後、この処理をタイムスタンプ付きスクリプトにまとめ、Cron のスケジュールを設定します。自動実行に関わるパスはすべて絶対パスにするため、対話型シェルの現在のディレクトリに依存しません。

マニフェストでバックアップ範囲を定義する

このステップでは、バックアップ対象を明確にし、確認しやすくするため、パスをプレーンテキストで列挙したマニフェストを作成します。

作業ディレクトリに移動します。

cd /home/labex/project/backup-lab

data ディレクトリからの相対パスを含むマニフェストを作成します。

cat > backup-manifest.txt <<'EOF'
config/app.conf
documents/runbook.txt
EOF

確認しやすいように、エントリに番号を付けて表示します。

nl -ba backup-manifest.txt

while ループを使って、列挙したすべてのソースが存在することを確認します。実行する前に、処理の構造を確認しておきましょう。

  • IFS= は、行の先頭や末尾にある空白をシェルが削除するのを防ぎます。
  • read -r item は、バックスラッシュを特別扱いせずに、1 行全体を item に読み込みます。
  • do ... done は、各行に対して繰り返し実行するコマンドを囲みます。
  • < backup-manifest.txt は、マニフェストをループの入力として渡します。
  • test -f は、対応するパスが通常のファイルかどうかを確認し、&& はその確認に成功した場合だけ ready を表示します。
while IFS= read -r item; do
  test -f "data/$item" && echo "ready: $item"
done < backup-manifest.txt

マニフェストにない documents/scratch.txt は、意図的にこの管理対象バックアップの範囲外に置かれています。

マニフェストからアーカイブを作成する

このステップでは、tar -T を使ってマニフェストからファイル名を読み込みます。-C data オプションにより、アーカイブ内のパスを短い相対パスにできます。

tar -czf backups/manual-backup.tar.gz -C data -T backup-manifest.txt

各オプションの意味は次のとおりです。

  • -c: アーカイブを作成します。
  • -z: gzip で圧縮します。
  • -f: 次に指定するアーカイブファイル名を使用します。
  • -C data: data を基準に処理します。
  • -T backup-manifest.txt: マニフェストからバックアップ対象のメンバーを読み込みます。

作成されたファイルを確認します。

ls -lh backups/manual-backup.tar.gz

アーカイブのタイムスタンプとサイズをソースファイルと比較します。

stat -c '%n size=%s modified=%y' backups/manual-backup.tar.gz data/config/app.conf data/documents/runbook.txt

展開せずにアーカイブを検証する

このステップでは、アーカイブを信頼して使用する前に内容を検証します。まず gzip ストリームをテストします。

gzip -t backups/manual-backup.tar.gz

何も出力されなければ、圧縮ストリームの整合性チェックに合格しています。次に、展開せずに tar のメンバーを一覧表示します。

tar -tzf backups/manual-backup.tar.gz | tee archive-contents.txt

保存した一覧をマニフェストと比較します。

diff -u backup-manifest.txt archive-contents.txt

差分が表示されなければ正常です。管理対象外の scratch ファイルが含まれていないことも確認します。

if tar -tzf backups/manual-backup.tar.gz | grep -qx 'documents/scratch.txt'; then
  echo "Unexpected scratch file found"
else
  echo "Archive scope is correct"
fi

指定したファイルを 1 つだけ復旧する

このステップでは、関係のないデータを上書きしないよう、指定したファイルだけを復旧します。設定ファイルを誤って削除した状況を再現します。

rm data/config/app.conf
test -e data/config/app.conf || echo "app.conf is missing"

config/app.conf だけを別の復旧用ディレクトリに展開します。

rm -rf restore/*
tar -xzf backups/manual-backup.tar.gz -C restore config/app.conf

復旧したファイルを確認し、元の作業場所に戻します。

cat restore/config/app.conf
cp restore/config/app.conf data/config/app.conf
cmp -s restore/config/app.conf data/config/app.conf && echo "Configuration restored"

アーカイブメンバーのうち、要求したファイルだけが展開されました。

タイムスタンプ付きバックアップスクリプトを作成する

このステップでは、タイムスタンプ付きのバックアップスクリプトを作成します。Cron は限られた環境でジョブを起動するため、無人実行用のスクリプト内では絶対パスを使用します。

backup.sh を作成します。

cat > backup.sh <<'EOF'
#!/bin/bash

source_dir=/home/labex/project/backup-lab/data
manifest=/home/labex/project/backup-lab/backup-manifest.txt
backup_dir=/home/labex/project/backup-lab/backups
timestamp=$(date +%Y%m%d-%H%M%S)
archive="$backup_dir/backup-$timestamp.tar.gz"

mkdir -p "$backup_dir"

if [ ! -d "$source_dir" ] || [ ! -f "$manifest" ]; then
  echo "Backup source or manifest is missing" >&2
  exit 1
fi

/bin/tar -czf "$archive" -C "$source_dir" -T "$manifest" || exit 1
/bin/tar -tzf "$archive" > "$archive.contents" || exit 1

echo "Created $archive"
exit 0
EOF

スクリプトに実行権限を付与し、Cron を待たずに今すぐテストします。

chmod u+x backup.sh
./backup.sh | tee last-backup.txt
ls -1 backups

タイムスタンプにより、実行ごとに一意のファイル名が付けられます。対応する .contents ファイルには、アーカイブに実際に含まれている内容が記録されます。

Cron スケジュールを設定して確認する

このステップでは、ユーザー用の Cron スケジュールを設定し、内容を確認します。crontab の 1 行は、5 つのスケジュール項目と、それに続くコマンドで構成されます。

位置 項目 通常の範囲
1 059
2 023
3 131
4 112
5 曜日 07、日曜日は 0 または 7

アスタリスク * は、その項目で許可されているすべての値を意味します。*/5 のようなステップ値は、その項目で 5 単位ごとに実行することを意味します。

minute hour day-of-month month day-of-week command

たとえば、*/5 * * * * は 5 分ごと、0 2 * * * は毎日 02:00 を意味します。

crontab -e を実行すると、エディターでユーザー用 crontab を開けます。確実な手順として、まず正しいことが分かっているエントリを準備してインストールし、その後に小さな対話編集を行います。絶対パスを使用し、標準出力と標準エラーの両方を記録するエントリを作成します。

cat > backup.crontab <<'EOF'
*/5 * * * * /home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
EOF

内容を確認してインストールします。

cat backup.crontab
crontab backup.crontab

次に、インストール済みの crontab を Nano で開きます。

EDITOR=nano crontab -e

スケジュールの 1 行上に次のコメントを追加します。

## LabEx managed backup schedule

Ctrl+O、続けて Enter を押して保存します。Ctrl+X を押して Nano を終了し、シェルに戻ります。crontab -l で Cron が実際に読み込む内容を確認し、その出力を保存します。

crontab -l | tee installed-crontab.txt

出力にはコメントが表示され、その次に 5 分ごとのエントリが続くはずです。インストール済みの結果を確認することで、スケジュールに依存する前に編集ミスを発見できます。

ログ記録をテストし、パーセント記号のエスケープを理解する

このステップでは、バックアップのログ記録をテストし、Cron におけるパーセント記号の特別な扱いを学びます。まず、スケジュールされたコマンドを手動で実行します。

/home/labex/project/backup-lab/backup.sh >> /home/labex/project/backup-lab/logs/backup.log 2>&1
tail -n 5 logs/backup.log
find backups -maxdepth 1 -type f -name 'backup-*.tar.gz' -printf '%f\n' | sort

タイムスタンプは backup.sh 内で生成されるため、通常の % 文字をそのまま使用できます。しかし、Cron は crontab のコマンド内にあるエスケープされていない % を特別に扱います。crontab の行に date を直接記述する場合は、各パーセント記号をバックスラッシュでエスケープしてください。

正しくエスケープした例を、参照用に保存します。

cat > cron-date-example.txt <<'EOF'
0 2 * * * /bin/echo "backup-$(/bin/date +\%Y\%m\%d-\%H\%M\%S)" >> /home/labex/project/backup-lab/logs/date-example.log 2>&1
EOF
cat cron-date-example.txt

現在インストールされているジョブは、よりシンプルなスクリプトベースのエントリのままです。絶対パスを使用し、すべてのアーカイブにタイムスタンプを付け、無人実行後に確認できるログを残します。

まとめ

マニフェストでバックアップ範囲を定義し、tar -T を使ってアーカイブを作成しました。さらに、展開せずにアーカイブを検証し、指定したファイルを 1 つだけ復旧しました。その後、絶対パスを使用するタイムスタンプ付きバックアップスクリプトを作成し、Cron スケジュールを設定して確認しました。また、無人実行時の出力をログにリダイレクトし、date を crontab のコマンドに直接記述する場合にパーセント記号をエスケープする必要がある理由も学びました。