世代管理バックアップ

指定された世代数に渡りバックアップを行う。

要件

  • 世代毎に【プレフィックス名】【日時分秒】の名称を持つディレクトリが作成される
    世代毎にディレクトリのコピーにより全バックアップ対象を取り出せる。
  • 必要最低限のディスク容量を占有する
    画像や動画ファイルは既圧縮でありバックアップ時の圧縮は不要。
    ハードリンクを使用し占有容量を最適化。
  • cronにより定期的に実行
  • Ubuntu 20.04LTS以降で実行可能

世代管理バックアップ

generational_backup.sh

#!/bin/bash

SRC_DIR=/path/to/data               #バックアップ元ルートディレクトリ
DEST_DIR=/path/to/backup_directory  #バックアップ先ルートディレクトリ
DIRECTORY_PREFIX=backup-
NUM_KEEP=5                      #保存世代数(>0)

#--- 開始 ---
echo "Backup start at $(date +%Y%m%d-%H%M%S)"

#--- 削除 ---
num_all=$(find $DEST_DIR -maxdepth 1 -type d | grep $DIRECTORY_PREFIX | wc -l)
num_removed=$((num_all-NUM_KEEP+1))
num_removed=$((num_removed<0?0:num_removed))
removed_directories=$(find $DEST_DIR -maxdepth 1 -type d | grep $DIRECTORY_PREFIX | sort -n | head -n $num_removed | tr '\n' ' ')
rm -r $removed_directories

#--- バックアップ ---
latest_backup=$(find $DEST_DIR -maxdepth 1 -type d | grep $DIRECTORY_PREFIX | sort -n | tail -n 1)      #最新バックアップディレクトリ名
rsync -avh --link-dest=$latest_backup $SRC_DIR/ $DEST_DIR/$DIRECTORY_PREFIX$(date +%Y%m%d-%H%M%S)

#--- 終了 ---
echo "Backup end at $(date +%Y%m%d-%H%M%S)"

2重起動の防止

スクリプトの実行中に再度起動されないようガードしておく。
cronがpgrepを実行すると自身のpidも検索対象となる。よって自身のPID(”$$”)が最も古いPIDであれば、より新しいプロセスは存在しないと判断することとする。

00 2 * * *     if [ "$$" = "`pgrep -fo generational_backup.sh`" ]; then /path/to/script/generational_backup.sh >> /path/to/backup/log_$(date +\%Y\%m\%d-\%H\%M\%S).txt; else echo "Backup canceled." >> /mnt/data_backup/log_$(date +\%Y\%m\%d-\%H\%M\%S).txt; fi

パスワードの記述

スクリプト中にデータベースのパスワード等を記述するとコマンド履歴やログ類に残ってしまう。第3者になるべく見れないように所有者だけが読み書き権限を持つファイルに記載しmysqldumpのコマンドの引数として渡す。
カレントディレクトリに依存せずにアカウント情報を参照するためにスクリプト自体のフルパスを取得する工夫を入れる。

mysqldump --defaults-extra-file=$(cd $(dirname $0); pwd)/【アカウント情報を含むファイル名】 ...