スケジュールされたバックアップとリカバリ

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 つのファイルを復元する

このステップでは、関係のないデータを上書きしないように、指定した 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 minute 059
2 hour 023
3 day of month 131
4 month 112
5 day of week 07。Sunday は 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

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

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 のコマンドに直接記述する場合にパーセント記号をエスケープする必要がある理由を学びました。