システムバックアップ


ディスクの論理破壊・物理破壊からシステムを守るために、システムバックアップを取る事は非常に大切です。

今まで一生懸命設定してきたデータを守るため、きちんとしたバックアップを取るようにしましょう。

正しいシステムバックアップ

システムバックアップについて誤った認識を持っている人がいるので、バックアップの重要性を説明していきたいと思います。

バックアップは外部メディアに保存しなければなりません

「ハードディスクの空いてるファイルシステムにバックアップを取ってるよ」

折角バックアップを取っても、同じハードディスクの空いている領域に保存してしまう人がいますが、それではバックアップの意味がありません。

バックアップはハードディスクの物理破壊からシステムを守るために行うのであって、ハードディスクが壊れた時に、一緒にバックアップも消失してしまっては意味がありません。

バックアップはかならず外部のメディアに保存するようにしましょう。

RAIDはシステムバックアップの代わりにはなりません

「RAIDでディスクを冗長構成にすればバックアップはいらないんじゃないの?」

RAIDという技術はディスクの物理破壊に対する備えであって、論理破壊には対応できません。

例えばRAID構成を取っているシステムで、ある重要な設定ファイルをrmしてしまった瞬間、RAIDを構成しているディスク全部からその設定ファイルが消えて無くなり、復元することは不可能です。

システムがウィルスに感染した際も、ウィルスのデータがRAIDディスク全体に広がってしまい、そこから正常な状態に戻すことは困難です。

RAIDではタイプミスによるファイルの消失や上書き、ウィルスによる感染などの論理破壊に対してはまったくの無力です。

バックアップメディア

バックアップメディアにはUSB接続タイプの2.5inch外付けHDDを選択しました。

大容量USBメモリや3.5inch外付けHDDも候補になったのですが、USBメモリでは容量あたりの価格がまだまだ高過ぎ、3.5inch外付けHDDでは本体が大きすぎACアダプタで外部から電源を取る必要がありました。

その点、2.5inch外付けHDDではUSBメモリより容量あたりの価格が低く、USBバスパワーだけで駆動できます。

実際は2.5inchのHDDが余っていたので外付けHDDケースの調達だけで済みました。

バックアップの方針

システムバックアップを取る際に考えなければならないのが「何処をどうやってどんな頻度で」というバックアップ方針です。

方針はシステムの使われ方やシステムの構成、バックアップメディアなどを考慮して決定します。

熟考の末、このシステムのバックアップは以下の方針としました。

  1. /swapを除いたすべてのファイルシステムをバックアップする
  2. バックアップはLVM Snapshotを使う
  3. 日曜日にフルバックアップを取得し、月~土曜日は差分バックアップとする
  4. バックアップの開始は毎日午前1時に実施

1.については、/usrや/binなどは新たにアプリケーションのインストールでもしなければファイル内容は変わらないので、毎日バックアップする必要はありませんが、後述のシェル作成でロジックを作りこむのが面倒なので、すべてのファイルシステムを取ることにしました。

2.では/swap以外のファイルシステムをLVMで作っているので、LVMのSnapshot機能でシステムを停止させずにバックアップが取得できます。

3.は自宅サーバでは毎日大量の更新があるわけではないので、毎日フルバックアップを取る必要は薄いでしょう。
フルバックアップには時間と大量のシステムリソースが必要なので普段は差分バックアップを取得することにしました。

4.はシステムにアクセスの少ない時間帯を選びました。

バックアップ方法

バックアップにはshellを使いcronで定期実行させます。

今回作ったのはbackup.shとbackup.lstの2つです。

実際に動作させるにはこの他にログ出力の為の共通関数shell_lib.shや、取得したバックアップを指定日数が経過したら削除するlog_lotate.shなども必要です。
(バックアップには直接関係無いのでここには載せませんが、欲しいという方がいればご連絡ください)

backup.sh

バックアップシェルの本体です。

/root/unyo/binディレクトに置き、同じディレクトリにあるbackup.lst(後述)で指定されたファイルシステムをバックアップします。

バックアップ先は外付けUSBハードディスクの/media/diskです。

日曜日にdumpレベル0(フルバックアップ)を取得し、その後は差分バックアップを取得します。

何らかの原因でバックアップが失敗した際にはroot宛てにエラーメッセージが送信されます。

#!/bin/bash
###########################################################
#<シェル名>             backup.sh
#<機能>                 ファイルシステムバックアップシェル(LVM対応版)
#<実行ユーザー>         root
#<起動方法>             cron
#<引数>                 N/A
#<入力ファイル>         backup.lst
#<出力ファイル>         backup.log
###########################################################
. /root/unyo/bin/shell_lib.sh

#-----------------------------
# 変数宣言
#-----------------------------
TODAY=`date +%Y%m%d`
TIME=`date +%T`
DUMP_LEVEL=`date +%w`
#DUMP_LEVEL="0"
SHELLNAME=`basename $0 .sh`
SHELL_DIR="/root/unyo/bin"
LOG_DIR="/root/unyo/log"
LIST_FILE="${SHELL_DIR}/${SHELLNAME}.lst"
LOG_FILE="${LOG_DIR}/${SHELLNAME}_${TODAY}.log"
BKUP_DIR="/media/disk"
MAIL_SHELL="mail_send -s"

msgcat I $LOG_FILE "Backup start"

#-----------
# メール用メッセージ作成
#-----------
SUBJECT="SYSTEM BACKUP FAILD"
MAIL_MSG1="SYSTEM BACKUP FAILD. Please Check LOG FILE"

#-----------------------------
# リストファイル存在確認
#-----------------------------
if [[ ! -f $LIST_FILE ]]
then
        msgcat E $LOG_FILE "$LIST_FILEがありません"
        $MAIL_SHELL "$SUBJECT" "file not found $LIST_FILE"
        exit 1
fi

#-----------------------------
# バックアップ先ディレクトリ存在確認
#-----------------------------

if [[ ! `mount | grep $BKUP_DIR` ]]
then
        echo "${TODAY} ${TIME} E バックアップ先ディレクトリがmountされていません" >> $LOG_FILE
        msgcat E $LOG_FILE "バックアップ先ディレクトリがmountされていません"
        $MAIL_SHELL "$SUBJECT" "not mounted backup directory"
        exit 1
fi

#-----------------------------
# メイン
#-----------------------------

grep -v "#" $LIST_FILE | while read LINE
do
        #-----------------------------
        # リストを変数に格納
        #-----------------------------
        SNAP_VG=`echo $LINE | awk -F':' '{print $1}'`
        SNAP_LV=`echo $LINE | awk -F':' '{print $2}'`
        SNAP_SIZE=`echo $LINE | awk -F':' '{print $3}'`
        SNAP_NAME="SNAP00"

        #-----------------------------
        # バックアップ元FSの確認
        #-----------------------------
        if [[ ! -n `mount | grep  "${SNAP_VG}-${SNAP_LV}"` ]]
        then
                msgcat E $LOG_FILE "${SNAP_VG}/${SNAP_LV}がmountされていません"
                $MAIL_SHELL "$SUBJECT" "not mounted ${SNAP_VG}/${SNAP_LV}"
                continue
        fi

        #-----------------------------
        # snapshot作成
        #-----------------------------
        msgcat I $LOG_FILE "/dev/${SNAP_VG}/${SNAP_NAME} を作成します"
        msgcat I $LOG_FILE "lvcreate --snapshot --size $SNAP_SIZE --name $SNAP_NAME /dev/$SNAP_VG/$SNAP_LV"
        lvcreate --snapshot --size=$SNAP_SIZE --name $SNAP_NAME /dev/$SNAP_VG/$SNAP_LV
        RC=$?

        if(($RC))
        then
                msgcat E $LOG_FILE "/dev/$SNAP_VG/$SNAP_NAMEの作成に失敗しました"
                $MAIL_SHELL "$SUBJECT" "can not create ${SNAP_VG}/${SNAP_NAME}"
                continue
        else
                msgcat I $LOG_FILE "/dev/$SNAP_VG/$SNAP_NAME を作成しました"
        fi

        #-----------------------------
        # dumpの実行
        #-----------------------------
        msgcat I $LOG_FILE "/dev/$SNAP_VG/$SNAP_NAME のDUMPを開始します"
        msgcat I $LOG_FILE "dump ${DUMP_LEVEL}uf ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY} /dev/${SNAP_VG}/${SNAP_NAME}"
        dump ${DUMP_LEVEL}uf ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY} /dev/${SNAP_VG}/${SNAP_NAME} >> $LOG_FILE
        RC=$?

        if(($RC))
        then
                msgcat E $LOG_FILE "/dev/${SNAP_VG}/${SNAP_LV}のdumpに失敗しました"
                $MAIL_SHELL "$SUBJECT" "can not dump ${SNAP_VG}/${SNAP_LV}"
                msgcat I $LOG_FILE "/dev/$SNAP_VG/$SNAP_NAME を削除します"
                msgcat I $LOG_FILE "lvremove -f /dev/${SNAP_VG}/${SNAP_NAME}"
                lvremove -f /dev/${SNAP_VG}/${SNAP_NAME} >> $LOG_FILE
                continue
        else
                msgcat I $LOG_FILE "/dev/${SNAP_VG}/${SNAP_LV} のdumpを作成しました"
        file ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY} >> $LOG_FILE
        fi

        #-----------------------------
        # snapshotの削除
        #-----------------------------
        msgcat I $LOG_FILE "/dev/$SNAP_VG/$SNAP_NAME を削除します"
        msgcat I $LOG_FILE "lvremove -f /dev/${SNAP_VG}/${SNAP_NAME}"
        lvremove -f /dev/${SNAP_VG}/${SNAP_NAME} >> $LOG_FILE
        RC=$?

        if(($RC))
        then
                msgcat E $LOG_FILE "${SNAP_VG}/$SNAP_LV/$SNAP_NAMEの削除に失敗しました"
                $MAIL_SHELL "$SUBJECT" "not deleted ${SNAP_VG}/${SNAP_NAME}"
                continue
        else
                msgcat I $LOG_FILE "$SNAP_VG/$SNAP_NAME を削除しました"
        fi

        #-----------------------------
        # backupファイルの圧縮
        #-----------------------------
        msgcat I $LOG_FILE "${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY}の圧縮を開始します"
        msgcat I $LOG_FILE "gzip ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY}"
        gzip ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY} >> $LOG_FILE
        RC=$?

        if(($RC))
        then
                msgcat E $LOG_FILE "${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY}の圧縮に失敗しました"
                $MAIL_SHELL "$SUBJECT" "can not compress ${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY}"
                continue
        else
                msgcat I $LOG_FILE "${BKUP_DIR}/backup_${SNAP_LV}_${DUMP_LEVEL}_${TODAY}を圧縮しました"
        fi

done

msgcat I $LOG_FILE "/var/lib/dumpdatesの内容を表示します"
cat /var/lib/dumpdates >> $LOG_FILE

msgcat I $LOG_FILE "Backup end"

backup.lst

バックアップを取得するファイルシステムのリストです。

###########################################################
#<シェル名>     backup.lst
#<機能>         ファイルシステムバックアップ対象リスト(LVM対応版)
#<実行ユーザー> N/A
#<起動方法>     N/A
#<引数>         N/A
#<入力ファイル> N/A
#<出力ファイル> N/A
###########################################################
#source vg:source lv:snap size
VG00:LV00:3G
VG00:LV01:5G
VG00:LV02:3G
VG00:LV03:4G
VG00:LV04:4G
VG00:LV05:3G

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


5 + = 12

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>