rsyncによるバックアップ
http://x68000.q-e-d.net/~68user/unix/pickup?rsync
http://www.itmedia.co.jp/enterprise/articles/0804/25/news034.html
tar を使う方法とかあるけど、rsync もなかなか良い。
オプションの -a はアーカイブモードで -rlptgoD と同じである。各オプションの意味は以下のとおり。
ディレクトリを再帰的にコピーする (-r) シンボリックリンクを、そのままシンボリックリンクとしてコピーする (-l) パーミッションをそのままコピーする (-p) タイムスタンプをそのままコピーする (-t) グループをそのままコピーする (-g) ファイルオーナー (所有者) をそのままコピーする (-o) デバイスファイルやを特殊ファイルを、そのままコピーする (-D)
rsync -av /foo/from_dir /bar/to_dir
sshサーバに転送するには
rsync -av -e ssh user@example.com:from_dir/ /foo/to_dir/
ファイル名の文字コードを変換しながら転送
http://rottarte.net/blog/archives/2847
--iconv=SRC-CHARSET,DEST-CHARSET
というオプションを使うとファイル名の文字コードを変換できる。
rsync -auv --iconv=EUC-JP,UTF8 ./ 123.123.123.123 :/dest/dir/
差分バックアップ
差分バックアップするには --link-dest オプションを使う
rsync -av --delete --link-dest=../dir1_bak0 ~/dir1/ ~/dir1_bak1
相対パスを利用する場合は、--link-destで指定するディレクトリは、コピー先ディレクトリからの相対パスになるの注意。
絶対パスを使うと安心。
--link-destは、このオプションで指定したディレクトリ以下とコピー元を比較し、ファイルの所有者、タイムスタンプ、パーミッションなどすべてが一致するファイルであれば、指定されたディレクトリ内のファイルのハードリンクを作成します(ファイルが一致しない場合は、ハードリンクではなくコピーが行われます)
ls -li
でハードリンクになっていることが確認できる。
サンプルシェル
#!/bin/sh export LANG=ja_JP.UTF-8 ############### # 環境変数 ############### nowTime=`date +%Y%m%d_%H%M%S` limit=5 sourcePath="/home/centos/temp/backup/src" backupBasePath="/home/centos/temp/backup/dest" destPath=${backupBasePath}/${nowTime} workPath=${backupBasePath}/work execListBackupBasePath="ls \"\${backupBasePath}\" | grep \"[0-9]\{8\}_[0-9]\{6\}\"" pidFile=/var/run/backup.pid mail="hoge@hoge.com" subject="[Backup Log] ${nowTime}" # LINE_SEP=' # ' LINE_SEP=$'\n' IFS_DEFAULT=$IFS ############## # 関数群 ############## # sendMail(){ # subjectBase64="" # lines=`echo -e ${subject} | fold -c10` # sep="" # IFS=${LINE_SEP} # for line in ${lines}; do # subjectBase64=${subjectBase64}${sep}"=?UTF-8?B?`echo -e ${line} | base64`?=" # sep="\n\t" # done # IFS=${IFS_DEFAULT} # #subject="${subjectBase64%\\n\\t}" # # echo -e ${subjectBase64} # body=`echo -e $1 | base64` # echo -e "To:${mail}\nSubject:${subjectBase64}\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: base64\n\n$body" | /usr/sbin/sendmail -t # } checkError(){ if [ $1 -ne 0 ]; then echo $2 # sendMail "バックアップ異常終了\n$2" exit $1 fi } checkProcess(){ if [ -f "${pidFile}" ]; then PID=`cat "${pidFile}" ` if (ps -e | awk '{print $1}' | grep ${PID} > /dev/null); then return 1 fi fi echo $$ > "${pidFile}" return 0 } judgeFullBackup() { local result=0 fullBackup=1 local countBackup=`eval ${execListBackupBasePath} | wc -l` if [ ${countBackup} -ne 0 ]; then fullBackup=0 beforeBackup=`eval ${execListBackupBasePath} | sort -r | head -n 1` result=$? beforeBackup="${backupBasePath}/${beforeBackup}" fi return ${result} } runBackup() { if [ -d "${workPath}" ]; then echo 作業用ディレクトリを削除します。 echo rm "${workPath}" rm -rf "${workPath}" result=$? checkError ${result} "作業用ディレクトリ削除に失敗しました。" fi if [ $fullBackup -eq 1 ]; then echo バックアップ種類 ベースバックアップ echo バックアップソース "${sourcePath}" echo バックアップ先 "${destPath}" else echo バックアップ種類 差分バックアップ echo バックアップソース "${sourcePath}" echo バックアップ比較元 "${beforeBackup}" echo バックアップ先 "${destPath}" fi echo ${LINE_SEP} if [ $fullBackup -eq 1 ]; then #(time rsync -av --chmod=ugo-w --delete "${sourcePath}/" "${workPath}/") (time rsync -av --delete "${sourcePath}/" "${workPath}/") else #(time rsync -av --chmod=ugo-w --delete --link-dest="${beforeBackup}" "${sourcePath}/" "${workPath}/") (time rsync -av --delete --link-dest="${beforeBackup}" "${sourcePath}/" "${workPath}/") fi result=$? checkError ${result} "バックアップに失敗しました。" mv "${workPath}" "${destPath}" result=$? checkError ${result} "作業ディレクトリの名前変更に失敗しました。" return 0 } deleteBackup() { IFS=$LINE_SEP local countBackup=`eval ${execListBackupBasePath} | wc -l` local countDelete=`expr ${countBackup} - ${limit}` if [ $countDelete -gt 0 ]; then local deleteDirs=`eval ${execListBackupBasePath} | sort | head -n ${countDelete}` for deleteDir in ${deleteDirs}; do deleteDir="${backupBasePath}/${deleteDir}" echo delete "${deleteDir}" (time rm -rf "${deleteDir}") done fi IFS=${IFS_DEFAULT} } #################### # メイン処理 #################### echo "#########################" echo backup start date "+%Y-%m-%d %H:%M:%S" echo "#########################" checkProcess result=$? checkError ${result} "多重起動エラー" # パスの存在チェック if [ ! -d "${sourcePath}" ]; then checkError 1 "${sourcePath}がありません。" fi if [ ! -d "${backupBasePath}" ]; then checkError 1 "${backupBasePath}がありません。" fi if [ -d "${destPath}" ]; then checkError 1 "${destPath}が既に存在しています。" fi # バックアップモード決定 judgeFullBackup result=$? checkError ${result} "バックアップモード決定に失敗しました。" # バックアップ実行 runBackup result=$? checkError ${result} "バックアップに失敗しました。" # 古いバックアップファイルを削除 deleteBackup echo "#########################" echo backup end date "+%Y-%m-%d %H:%M:%S" echo "#########################" rm "${pidFile}" # sendMail "バックアップ正常終了" echo "バックアップ正常終了"
cron を使う場合の注意
cron で実行すると LANG環境変数が設定されずにログファイル等が化けることがある。
cron から実行されるシェル等の冒頭で
export LANG=ja_JP.UTF-8
で文字コードを設定しておくと良い。
ファイルの変更検出について
rsyncは通常のオプションでは、日付とサイズによってファイルの変更検出を行う。
ファイルの中身で変更検出を行う場合は
-c または --checksum
転送要否を決定する際、タイムスタンプとファイルサイズではなく、128bit の MD4 チェックサムを用いて同一ファイルか否かをチェックする。
を使う。
バックアップ領域の書込権限
可能であれば、バックアップ領域は読取専用にしておく。
通常はroot権限でも書込出来ないように読取専用でマウントしておく。
バックアップ時に書込み可能にする。
方法1
通常は
mount -o ro /dev/sdb1 /mnt/backup
にしておき、バックアップ時に
mount -o remount,rw /mnt/backup
にする。ただし、バックアップ中は書込み可能になる
方法2
名前空間を使ってバックアッププロセス以外は書込不可にする。
通常は
mount -o ro /dev/sdb1 /mnt/backup
にしておく。バックアッププロセスを
unshare -m
で実行して分離している状態で
mount -o remount,rw /mnt/backup
にする。
[カテゴリ: OS > Linux]
[通知用URL]
Tweet
最終更新時間:2017年12月29日 22時22分28秒