LANDISK HACKING DIARY
Since2005/8/17
TOPへ戻る
     INDEX
   
1. dump で HDD(master)から HDD(slave)へバックアップする
2. インクリメンタルバックアップ




 
     dump で HDD(master)から HDD(slave)へバックアップする
 
dump は、ファイルシステム単位でのバックアップを行うことができ、更新されたファイルだけをバックアップするインクリメンタルバックアップも行うことができる。アーカイヴに要する時間も、他の方法にくらべて非常に高速であるという特徴がある。しかしながら、特定のファイルをアーカイヴの対象から除外するような機能は用意されていない(chattr による attirbute属性を使えば可能)。バックアップには様々なコマンドやツールがあるが、面倒くさくてつい cp や tar コマンドなどに頼って自作のシェルスクリプトで部分バックアップを行ってきたが、今回、重い腰をあげて dump コマンドに関して覚えてみることにした。ここでは、1台のマシンに同容量の2台のハードディスクを挿入し、プライマリMaster から プライマリSlave へバックアップしてみることにする。

まず、/etc/fstab の第5フィールドにバックアップしておきたいファイルシステムに「1」のフラグを立てておく。swap や /proc などはバックアップする必要がないので「0」にしておく。

# This file is edited by fstab-sync - see 'man fstab-sync' for details
LABEL=/                 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
none                    /dev/pts                devpts  gid=5,mode=620  0 0
none                    /dev/shm                tmpfs   defaults        0 0
LABEL=/home             /home                   ext3    defaults        1 2
none                    /proc                   proc    defaults        0 0
none                    /sys                    sysfs   defaults        0 0
LABEL=/usr              /usr                    ext3    defaults        1 2
LABEL=/var              /var                    ext3    defaults        1 2
LABEL=SWAP-hda7         swap                    swap    defaults        0 0
/dev/hdd                /media/cdrom            auto    pamconsole,exec,noauto,managed 0 0
/dev/fd0                /media/floppy           auto    pamconsole,exec,noauto,managed 0 0

■バックアップしないファイルの除外

attribute を設定し、バックアップしないファイルを除外する。d のフラグが立ったディレクトリはバックアップ対象から除外することができる。ただし level 0 のフルダンプの際デフォルトではこの指定は無視され、実際に効果があるのは level 1 以降のインクリメンタルバックアップの時になります。もし level 0 の時も同じ効果を得たい場合は dump の h オプションで指定する必要があります。バックアップする必要のないディレクトリは、squid のキャッシュや、ウィルスメールを格納するディレクトリ、/tmp ディレクトリなどがある。

# chattr -R +d /var/spool/squid
# lsattr /var/spool/squid
------d------ /var/spool/squid/swap.state
------d------ /var/spool/squid/03
------d------ /var/spool/squid/06
------d------ /var/spool/squid/05
------d------ /var/spool/squid/02
・・・省略

■dumpの書式

# dump -0uf [ バックアップ先 ] [ バックアップ元 ]

■dump のオプション

0 〜 9 : dump level
h : nodump アトリビュートが影響する dump level
f : 出力先ファイル(テープ)の指定
u : /etc/dumpdates を更新する

以上の点を踏まえ、実際にバックアップを行ってみる。フルバックアップ時には、できる限りシングルユーザーモードで実行するようにする。これは、バックアップ中にファイルに変更があった場合に、そのファイルがバックアップされるとは限らないからである。とりあえず、fdisk で同容量のパーティションを予め作成しておく(以下の例では swap 領域も作成しているが実際は必要ない)。

# fdisk -l

Disk /dev/hda: 27.2 GB, 27201871872 bytes
255 heads, 63 sectors/track, 3307 cylinders
Units = シリンダ数 of 16065 * 512 = 8225280 bytes

デバイス Boot      Start         End      Blocks   Id  System
/dev/hda1   *           1          13      104391   83  Linux
/dev/hda2              14         535     4192965   83  Linux
/dev/hda3             536         666     1052257+  83  Linux
/dev/hda4             667        3307    21213832+   5  拡張領域
/dev/hda5             667        2719    16490691   83  Linux
/dev/hda6            2720        3241     4192933+  83  Linux
/dev/hda7            3242        3306      522081   82  Linux スワップ

Disk /dev/hdb: 30.0 GB, 30003241472 bytes
255 heads, 63 sectors/track, 3647 cylinders
Units = シリンダ数 of 16065 * 512 = 8225280 bytes

デバイス Boot      Start         End      Blocks   Id  System
/dev/hdb1               1          13      104391   83  Linux
/dev/hdb2              14         535     4192965   83  Linux
/dev/hdb3             536         666     1052257+  83  Linux
/dev/hdb4             667        3307    21213832+   5  拡張領域
/dev/hdb5             667        2719    16490691   83  Linux
/dev/hdb6            2720        3241     4192933+  83  Linux
/dev/hdb7            3242        3306      522081   83  Linux

ファイルシステムのフォーマット。

# mkfs.ext3 /dev/hdb1
# mkfs.ext3 /dev/hdb2
# mkfs.ext3 /dev/hdb3
# mkfs.ext3 /dev/hdb5
# mkfs.ext3 /dev/hdb6
# mkswap /dev/hdb7

ファイルシステム(バックアップ先)のマウント。

# mkdir -p /mnt/{hdb1,hdb2,hdb3,hdb5,hdb6}
# mount -t ext3 /dev/hdb1 /mnt/hdb1
# mount -t ext3 /dev/hdb2 /mnt/hdb2
# mount -t ext3 /dev/hdb3 /mnt/hdb3
# mount -t ext3 /dev/hdb5 /mnt/hdb5
# mount -t ext3 /dev/hdb6 /mnt/hdb6
# df -h
Filesystem          サイズ  使用  残り 使用% マウント位置
/dev/hda3            1012M  265M  696M  28% /
/dev/hda1              99M   11M   83M  12% /boot
none                  252M     0  252M   0% /dev/shm
/dev/hda5              16G  293M   15G   2% /home
/dev/hda2             4.0G  2.7G  1.2G  70% /usr
/dev/hda6             4.0G  1.1G  2.8G  28% /var
/dev/hdb1              99M    5M   93M  12% /mnt/hdb1
/dev/hdb2             4.0G  465M  3.3G  13% /mnt/hdb2
/dev/hdb3            1012M   34M  927M   4% /mnt/hdb3
/dev/hdb5              16G   76M   15G   1% /mnt/hdb5
/dev/hdb6             4.0G   41M  3.7G   2% /mnt/hdb6

試しに、/dev/hda1 をバックアップしてみる。-u オプションは増分バックアップ(インクリメンタルバックアップ)するには必須。/dev/hda1(/boot)を、/mnt/hdb1/dump-hda1.bkup としてバックアップしている。

# dump -0uf /mnt/hdb1/dump-hda1.bkup /dev/hda1

上記の例では、イメージファイルとして/dev/hdb にバックアップしているが、どうせなら dump → restore の処理を同時に実行し、/dev/hdb にファイルやディレクトリが展開(復元)された状態にしておいたほうがシステム復元時により楽になる。そのためには、以下のように、dump と restore コマンドをパイプで繋ぎ、一度に処理するといいだろう。「-f -」でパイプに流せる。注意すべき点は、resotre コマンドを実行した際に、ファイルはカレントディレクトリに展開されるため、予めリストアしたい位置(PATH)に移動しておく必要がある。restore コマンド の -r オプションは「復元」、-f は「ファイル指定」を意味する。

# cd /mnt/hdb1 ; dump -0uf - /dev/hda1 | restore -rf -
# cd /mnt/hdb2 ; dump -0uf - /dev/hda2 | restore -rf -
# cd /mnt/hdb3 ; dump -0uf - /dev/hda3 | restore -rf -
# cd /mnt/hdb5 ; dump -0uf - /dev/hda5 | restore -rf -
# cd /mnt/hdb6 ; dump -0uf - /dev/hda6 | restore -rf -

※インクリメンタルバックアップを行う必要がないのであれば、restoresymtable を削除する。この状態で、コピー元とコピー先の容量が同じであることを確認する。

# rm -rf /mnt/{hdb1,hdb2,hdb3,hdb5,hdb6}/restoresymtable
# df -h
Filesystem          サイズ  使用  残り 使用% マウント位置
/dev/hda3            1012M  265M  696M  28% /
/dev/hda1              99M   11M   83M  12% /boot
none                  252M     0  252M   0% /dev/shm
/dev/hda5              16G  293M   15G   2% /home
/dev/hda2             4.0G  2.7G  1.2G  70% /usr
/dev/hda6             4.0G  1.1G  2.8G  28% /var
/dev/hdb1              99M   11M   83M  12% /mnt/hdb1
/dev/hdb2             4.0G  2.7G  1.2G  70% /mnt/hdb2
/dev/hdb3            1012M  265M  696M  28% /mnt/hdb3
/dev/hdb5              16G  292M   15G   2% /mnt/hdb5
/dev/hdb6             4.0G  1.1G  2.8G  28% /mnt/hdb6

バックアップを終えたら、/etc/dumpdates を確認してみる。左から順に、[ バックアップしたファイルシステム ] [ ダンプレベル ] [ バックアップした日付 ] という形式で記述される。このファイルは、インクリメンタルバックアップの際にdumpレベルを調べるために使用され、dumpコマンドに-uオプションを付けると、/etc/dumpdatesファイルが更新される。

 # cat /etc/dumpdates
/dev/hda1 0 Mon Sep 19 02:08:23 2005 +0900
/dev/hda2 0 Mon Sep 19 02:11:46 2005 +0900
/dev/hda3 0 Mon Sep 19 02:48:27 2005 +0900
/dev/hda5 0 Mon Sep 19 02:55:22 2005 +0900
/dev/hda6 0 Mon Sep 19 02:59:20 2005 +0900



 
     インクリメンタルバックアップ
 
インクリメンタルバックアップを1日に1回実行するようにしてみる。さてさて、ここから記述することも筆者は自信がありません。完全な我流なので本当にこれでいいのかどうかもよくわからないのであくまで自己責任で読んでください。なにせ、テープへのバックアップを前提とした文献が多かったので…。バックアップ本でも1冊買ってみるのもいいかもしれませんね。

筆者のバックアップの考え方としては、

 1. いくら深夜とはいえ、毎日フルバックアップするほどの負荷をシステムにかけたくない。
 2. 日曜日の深夜にフルバックアップし、月曜日〜土曜日までは増分バックアップする。
 3. /dev/hda と /dev/hdb が常に同期するようにする。


インクリメンタルバックアップの本来の方法としては、ダンプレベル 1〜9 までの整数を用いて、1日に更新された分だけをテープにバックアップしていき、復元する際も、増分バックアップした 1〜9 のレベルのものを順番に復元していかなければ完全な復元にはならないんだと思います(違う?)。もし、筆者の認識が間違っていないとすれば、復元する際に筆者はこんな面倒なことはできません。ということで、筆者の場合は、/dev/hda のディスクと /dev/hdb のディスクが常に同じ状態に保っておくようにし、特定のファイルを誤って削除してしまった場合などにいつでも取り出せるような環境を構築していきます。勿論、/dev/hdb は常にオンライン状態にしておきます。電気代が気になる方は以降は読む必要がありませんので悪しからず。

まず、フルバックアップを最初にとっておく。同時に、展開(復元)もしてしまいます。ちまちまコマンドを打つのも面倒なので、シェルスクリプトでフルバックアップします。それでは、ちょっと散歩してきます。

# vi dump0.sh

#!/bin/sh
# dump0.sh

cd /mnt/hdb1 ; dump -0uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -0uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -0uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -0uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -0uf - /dev/hda6 | restore -rf -

exit 0;

# chmod +x dump0.sh
# ./dump0.sh

ふー、ただいま。/etc/dumpdates を見てみる。きちんとフルバックアップできているようですね。

# cat /etc/dumpdates
/dev/hda1 0 Mon Sep 19 13:57:36 2005 +0900
/dev/hda2 0 Mon Sep 19 13:57:40 2005 +0900
/dev/hda3 0 Mon Sep 19 14:28:27 2005 +0900
/dev/hda5 0 Mon Sep 19 14:31:49 2005 +0900
/dev/hda6 0 Mon Sep 19 14:35:33 2005 +0900

以降は、dump がどこまで賢くバックアップできるのか、実験してみます。まず、WAVファイルを /home/kororo に置いておく。

# cd /home/kororo/ ; ls
Maildir VOICE001.wav autorun backup config named public_html user_prefs

レベル1 のインクリメンタルバックアップを行います。/dev/hdb5/kororo に移動して、VOICE001.wav があれば、インクリメンタルは成功です。

# cd /mnt/hdb5 ; dump -1uf - /dev/hda5 | restore -rf -
# cd /mnt/hdb5/kororo ; ls
Maildir VOICE001.wav autorun backup config named public_html user_prefs

今度は、VOICE001.wav を削除して、レベル2 として dump してみます。今度は、バックアップ先にも VOICE001.wav が消えていなければならないはずです。問題なく消えているようです。

# rm -rf /home/kororo/VOICE001.wav
# cd /mnt/hdb5 ; dump -2uf - /dev/hda5 | restore -rf -
# ls
Maildir autorun backup config named public_html user_prefs

第2の実験として、ファイルサイズのわずかな違いも認識できるのか試してみることにする。sshd_config を kororo のホームディレクトリにコピーし、レベル3としてバックアップする。

# cp /usr/local/etc/sshd_config /home/kororo/
# cd /mnt/hdb5 ; dump -3uf - /dev/hda5 | restore -rf -
# cd /mnt/hdb5/kororo ; ls
Maildir autorun backup config named public_html sshd_config user_prefs

/home/kororo/sshd_config の最終行に「a」と1文字加えてみます。その後で、レベル4 としてダンプしてみる。バックアップ先のファイルを見てみると、確かに「a」という文字が追加されたsshd_config が正常にバックアップされたことを確認しました。

# vi /home/kororo/sshd_config
省略…
a

# cd /mnt/hdb5 ; dump -4uf - /dev/hda5 | restore -rf -
# tail /mnt/hdb5/kororo/sshd_config

# override default of no subsystems
Subsystem sftp /usr/local/libexec/sftp-server
a

つまり…追加したファイルもバックアップ先に追加され、削除したファイルもバックアップ先から削除される。同期ができることになる。よって、以下のようにスケジューリングすればいいわけだ。日曜日にダンプレベル 0 のフルバックアップを行う。月曜〜土曜はインクリメンタルでレベルをひとつづづあげながらバックアップしていく(なぜなら、レベルを1つづつあげてバックアップしていかないとエラーが発生するからだ)。このバックアップスケジュールを cron に登録してしまえば、全て自動化できる。cron でも、「0」は日曜日を意味しているので、どうせなら cron の曜日とダンプレベルをあわせてしまったほうがわかりやすいだろう。

日曜 | 月曜 | 火曜 | 水曜 | 木曜 | 金曜 | 土曜
 0      1     2      3     4     5      6

まず、毎日実行するための、シェルスクリプトを7つ作成する(シェルスクリプトには詳しくないので7つも用意するだけです。ひとつのファイルで出来る方なら…もっとも出来る方なら筆者の真似はしないでしょう)。

# vi dump0.sh

#!/bin/sh
# dump0.sh

cd /mnt/hdb1 ; dump -0uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -0uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -0uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -0uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -0uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump1.sh

#!/bin/sh
# dump1.sh

cd /mnt/hdb1 ; dump -1uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -1uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -1uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -1uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -1uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump2.sh

#!/bin/sh
# dump2.sh

cd /mnt/hdb1 ; dump -2uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -2uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -2uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -2uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -2uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump3.sh

#!/bin/sh
# dump3.sh

cd /mnt/hdb1 ; dump -3uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -3uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -3uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -3uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -3uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump4.sh

#!/bin/sh
# dump4.sh

cd /mnt/hdb1 ; dump -4uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -4uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -4uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -4uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -4uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump5.sh

#!/bin/sh
# dump5.sh

cd /mnt/hdb1 ; dump -5uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -5uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -5uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -5uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -5uf - /dev/hda6 | restore -rf -

exit 0;
--------------------------------------------
# vi dump6.sh

#!/bin/sh
# dump6.sh

cd /mnt/hdb1 ; dump -6uf - /dev/hda1 | restore -rf -
cd /mnt/hdb2 ; dump -6uf - /dev/hda2 | restore -rf -
cd /mnt/hdb3 ; dump -6uf - /dev/hda3 | restore -rf -
cd /mnt/hdb5 ; dump -6uf - /dev/hda5 | restore -rf -
cd /mnt/hdb6 ; dump -6uf - /dev/hda6 | restore -rf -

exit 0;

実行権を付与する。

# chmod +x dump*.sh

上記で作成したスクリプトを cron に登録し、指定の曜日の深夜5時5分に実行されるようにする。ログは、ダンプコマンド実行時に開始時間と終了時間が記述されるので追記する必要はないだろう。

# vi /etc/crontab
05 5 * * 0 root (/usr/local/bin/dump6.sh > /var/log/dump6.log 2>&1) > /dev/null
05 5 * * 1 root (/usr/local/bin/dump0.sh > /var/log/dump0.log 2>&1) > /dev/null
05 5 * * 2 root (/usr/local/bin/dump1.sh > /var/log/dump1.log 2>&1) > /dev/null
05 5 * * 3 root (/usr/local/bin/dump2.sh > /var/log/dump2.log 2>&1) > /dev/null
05 5 * * 4 root (/usr/local/bin/dump3.sh > /var/log/dump3.log 2>&1) > /dev/null
05 5 * * 5 root (/usr/local/bin/dump4.sh > /var/log/dump4.log 2>&1) > /dev/null
05 5 * * 6 root (/usr/local/bin/dump5.sh > /var/log/dump5.log 2>&1) > /dev/null

今現在、執筆している曜日が月曜日なので、ダンプレベル1(月曜日)まで終わらせておく。明日、起きてから /etc/dumpdates を見て、ダンプレベル 2(火曜日)の出力が書き込まれていれば無事にバックアップ成功である。我ながら、意外と完璧な気がする。まぁ、1週間経ってみないと完全に成功したとはいえないが。

# ./dump1.sh
# cat /etc/dumpdates 
/dev/hda1 0 Mon Sep 19 13:57:36 2005 +0900
/dev/hda2 0 Mon Sep 19 13:57:40 2005 +0900
/dev/hda3 0 Mon Sep 19 14:28:27 2005 +0900
/dev/hda5 0 Mon Sep 19 18:03:57 2005 +0900
/dev/hda6 0 Mon Sep 19 14:35:33 2005 +0900
/dev/hda1 1 Mon Sep 19 18:11:42 2005 +0900
/dev/hda2 1 Mon Sep 19 18:11:45 2005 +0900
/dev/hda3 1 Mon Sep 19 18:12:57 2005 +0900
/dev/hda5 1 Mon Sep 19 18:13:33 2005 +0900
/dev/hda6 1 Mon Sep 19 18:14:58 2005 +0900



     参考文献
 
⇒Linux: dump and restore mini-HOWTO





TOPへ戻る
 
Copyright © KORO All Rights Reserved.