ccollect という rsync の --link-dest オプションによるハードリンクをうまく使って差分バックアップをしてくれるツールでバックアップ設定をしました。
インストール
deb パッケージは存在しないので、まず git clone https://github.com/ungleich/ccollect ~/src/github.com/ungleich/ccollect などで最新 (現時点で 1.0) の ccollect を github のミラーから取得します。
本家 の download ページにある tarball は 0.8 まででちょっと古いです。
共通設定
設定は CCOLLECT_CONF (デフォルトは /etc/ccollect) の中に置いていきます。
共通設定は defaults の中に、バックアップごとの設定は sources の中に置いていきます。
バックアップ保存回数の設定
defaults/intervals の中に適当なファイル名でバックアップの保存回数を設定していきます。
daily などの名前をつけることが多いようですが、 ccollect 自体に毎日自動実行する機能があるわけではないので、自前で cron などを使って実行する必要が有ります。
sudo mkdir -p /etc/ccollect/defaults/intervalsecho 10 | sudo tee /etc/ccollect/defaults/intervals/dailyecho 24 | sudo tee /etc/ccollect/defaults/intervals/monthlyecho 10 | sudo tee /etc/ccollect/defaults/intervals/weekly
ここでは日時バックアップと週次バックアップは 10 回分、月次バックアップは 2 年分保存するようにしてみました。
不完全なバックアップの削除
ccollect では構造化された設定ファイルをパースするのではなく、簡単な内容のファイルの中身が設定値になっていたり、ファイルの存在がフラグとなっていたりするようになっています。
ここでは rsync の途中で ssh が切れたなどの理由で不完全なバックアップができてしまった時に削除するフラグを設定します。
sudo touch /etc/ccollect/defaults/delete_incomplete
ローカルのバックアップ設定の追加
まず動作確認も兼ねて、ローカルのバックアップを取る設定を追加してみます。
sudo mkdir -p /etc/ccollect/sources/$(hostname)-homeecho '/home' | sudo tee /etc/ccollect/sources/$(hostname)-home/sourceecho "/srv/backup/$(hostname)-home" | sudo tee /etc/ccollect/sources/$(hostname)-home/destination
バックアップから除外するファイルも設定してみます。 除外指定ということを明示するために - をつけていますが、つけずにパターンだけでもこの場合は同じです。 exclude ファイルの書式の詳細は rsync "--exclude-from" で検索して調べてください。
echo '- *.swp' | sudo tee /etc/ccollect/sources/$(hostname)-home/excludeecho '- *~' | sudo tee -a /etc/ccollect/sources/$(hostname)-home/exclude
今回は関係ないかもしれませんが、 / パーティションなどをバックアップする時にはつけた方が良い --one-file-system オプションも追加しておきます。
echo '--one-file-system' | sudo tee /etc/ccollect/sources/$(hostname)-home/rsync_options
サマリー表示を有効にしておきます。 初回実行なので詳細表示も有効にしてみます。
sudo touch /etc/ccollect/sources/$(hostname)-home/summarysudo touch /etc/ccollect/sources/$(hostname)-home/verbose
初回バックアップ実行
destination ファイルで指定したバックアップ先ディレクトリは自動作成されないので、手動で作成してバックアップを実行します。 2 回実行してちゃんと差分バックアップになっているのを確認します。
sudo mkdir -pv $(cat /etc/ccollect/sources/*/destination)sudo ~/src/github.com/ungleich/ccollect/ccollect daily $(hostname)-homesudo ~/src/github.com/ungleich/ccollect/ccollect daily $(hostname)-home
容量も 2 倍になっていないのを確認します。
sudo du -s /srv/backup/$(hostname)-home /home
動作確認ができたので、詳細表示オプションを削除しておきます。
sudo rm /etc/ccollect/sources/$(hostname)-home/verbose
リモートからのバックアップ設定の追加
source にリモートホストを設定する以外はローカルの設定と同様に設定していきます。
sudo mkdir /etc/ccollect/sources/vps-etcecho /srv/backup/vps-etc | sudo tee /etc/ccollect/sources/vps-etc/destinationecho root@vps.example.jp:/etc | sudo tee /etc/ccollect/sources/vps-etc/sourceecho '- *.swp' | sudo tee -a /etc/ccollect/sources/vps-etc/excludeecho '- *~' | sudo tee -a /etc/ccollect/sources/vps-etc/excludesudo touch /etc/ccollect/sources/vps-etc/summary
ネットワーク的につながらない時はバックアップが失敗するので、事前チェックするようにします。
sudoedit /etc/ccollect/sources/vps-etc/pre_execsudo chmod +x /etc/ccollect/sources/vps-etc/pre_exec
pre_exec の内容は以下の通りです。 ccollect のドキュメントの Testing for host reachabilty を参考にしています。
#!/bin/sh
set -e
cur_conf_dir="${CCOLLECT_CONF:-/etc/ccollect}/sources/$name"
SRC_HOST=`cat "$cur_conf_dir/source" | cut -d"@" -f2 | cut -d":" -f1`
ping -c1 -q "$SRC_HOST" || exit $?
ssh 設定
セキュリティ的にはあまり好ましくないのですが、バックアップ用に root から root に ssh で接続できるようにします。
まず、バックアップ先のローカルのマシンで root の ssh 用の鍵を作成します。
-
sudo ls -al /root/.sshで root に ssh の鍵がないのを確認したらsudo ssh-keygenで生成します。存在する場合は別のファイル名で生成してsudoedit /root/.ssh/configでIdentityFileを設定しておきます。自動実行で使用するので、パスフレーズは空にしておきます。 - ssh のポート番号を変更しているなど、別途設定が必要な場合は
sudoedit /root/.ssh/configで設定しておくのを忘れないように注意が必要です。 -
sudo cat /root/.ssh/id_rsa.pubで公開鍵を表示してコピーしておきます。
続いて、バックアップ対象の VPS (バックアップ元) の方で ssh を許可する設定をします。
-
sudo install -m700 -d /root/.sshで/root/.sshがなければ作成します。 -
sudoedit /root/.ssh/authorized_keysで接続を許可する鍵として、先ほどコピーした公開鍵を貼り付けます。 - 必要に応じて
from="pattern-list"やno-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwardingなどの制限も追加しておきます。 -
sudoedit /etc/ssh/sshd_configでPermitRootLoginをno以外にします。例えばwithout-passwordにしておきます。 -
sudoedit /etc/ssh/sshd_configでAllowUsersによる制限をしている時はAllowUsers root@接続元IPアドレスを追加しておきます。接続元 IP アドレスが固定ではない場合は、セキュリティ的に弱くなりますがAllowUsers rootで許可します。 -
/etc/ssh/sshd_configの設定を変更した場合はsudo service ssh restartで反映させておきます。
設定ができたら、接続元 (バックアップ先のローカルのマシン) から ssh の接続確認をします。
-
sudo ssh root@vps.example.jp hostnameなどで ssh 接続ができることの確認とホスト鍵の確認を済ませておきます。
初回バックアップ実行
ローカルでのバックアップと同様にバックアップ先ディレクトリを作成してからバックアップを実行します。
sudo mkdir -pv $(cat /etc/ccollect/sources/*/destination)sudo ~/src/github.com/ungleich/ccollect/ccollect daily vps-etcsudo ~/src/github.com/ungleich/ccollect/ccollect daily vps-etc
リモートからの一般ユーザー権限でのバックアップ設定の追加
dokku で persistent storage としてボリュームマウントを使っているとファイルの所有者とグループがアプリケーションのデプロイのたびに変わってしまって、差分バックアップに支障が出そうだったので、一般ユーザーでのバックアップも設定しました。
XDG Base Directory Specification の XDG_CONFIG_HOME を参考にして ~/.config 以下に /etc 以下と同じ構造で設定を作成することにしました。
mkdir -p ~/.config/ccollect/defaults/intervalsecho 10 > ~/.config/ccollect/defaults/intervals/dailyecho 24 > ~/.config/ccollect/defaults/intervals/monthlyecho 10 > ~/.config/ccollect/defaults/intervals/weeklymkdir -p ~/.config/ccollect/sources/vps-srvecho /srv/backup/vps-srv > ~/.config/ccollect/sources/vps-srv/destinationecho vpsuser@vps.example.jp:/srv > ~/.config/ccollect/sources/vps-srv/sourceecho '- *.swp' > ~/.config/ccollect/sources/vps-srv/excludeecho '- *~' >> ~/.config/ccollect/sources/vps-srv/excludetouch ~/.config/ccollect/sources/vps-srv/summary
ネットワーク的につながらない時はバックアップが失敗するので、事前チェックするようにします。
editor ~/.config/ccollect/sources/vps-srv/pre_execchmod +x ~/.config/ccollect/sources/vps-srv/pre_exec
pre_exec の内容は以下の通りです。 「リモートからのバックアップ設定の追加」で作成したものと全く同じ内容です。
#!/bin/sh
set -e
cur_conf_dir="${CCOLLECT_CONF:-/etc/ccollect}/sources/$name"
SRC_HOST=`cat "$cur_conf_dir/source" | cut -d"@" -f2 | cut -d":" -f1`
ping -c1 -q "$SRC_HOST" || exit $?
初回バックアップ実行
一般ユーザー権限でバックアップするので、バックアップ先ディレクトリを chown しておきます。
ssh vpsuser@vps.example.jp で一度接続してホスト鍵の確認なども終わらせておきます。
設定ファイルの場所が違うので、環境変数 CCOLLECT_CONF を設定しつつ実行します。
sudo mkdir -pv $(cat ~/.config/ccollect/sources/*/destination)sudo chown $(id -u) /srv/backup/vps-srvenv CCOLLECT_CONF=$HOME/.config/ccollect ~/src/github.com/ungleich/ccollect/ccollect daily vps-srvenv CCOLLECT_CONF=$HOME/.config/ccollect ~/src/github.com/ungleich/ccollect/ccollect daily vps-srv
バックアップ自動実行設定
cron で毎日自動バックアップが動くように設定します。 時間がかかるので、 cron.daily のファイルの中でも最後に実行されるように zz- で始まる名前にしています。 そして、パッケージで入れたファイルと区別できるように local という文字列を名前に入れています。
その際、保存回数が一番多くて保存期間が長い monthly を優先するようにしてみました。
ログ保存用のディレクトリは一般的な debian の流儀に合わせて adm グループのみ読めるようにしています。 install コマンドについては installコマンドでコマンド数を減らす を参考にしてください。
ログは rotate などはせずに全部残して、 tools/ccollect_analyse_logs でエラーや警告があれば cron からのメールとして飛ぶようにしました。 その際、 tools/ccollect_analyse_logs の exit status が grep の exit status そのままなので、エラーの有無と逆の意味に感じられてしまうので、反転するようにしました。
sudoedit /etc/cron.daily/zz-local-ccollectsudo chmod +x /etc/cron.daily/zz-local-ccollect
/etc/cron.daily/zz-local-ccollect:
#!/bin/sh
INTERVAL=daily
if [ 7 = "$(date +%u)" ]; then
INTERVAL=weekly
fi
if [ 01 = "$(date +%d)" ]; then
INTERVAL=monthly
fi
mkdir -p /var/log/ccollect
LOGDIR="/var/log/ccollect"
LOGFILE="$LOGDIR/$(date +%Y%m%d-%H%M).log"
LOCALUSER="localuser"
CCOLLECT_DIR="/home/$LOCALUSER/src/github.com/ungleich/ccollect"
install -m750 -oroot -gadm -d "$LOGDIR"
{
su - "$LOCALUSER" -c 'env CCOLLECT_CONF=$HOME/.config/ccollect '"$CCOLLECT_DIR"'/ccollect -a '"$INTERVAL"
"$CCOLLECT_DIR/ccollect" -a "$INTERVAL"
} >"$LOGFILE" 2>&1
if /bin/sh "$CCOLLECT_DIR/tools/ccollect_analyse_logs" "we" < "$LOGFILE"; then
# found
exit 1
else
# not found
exit 0
fi
リモートの dokku の home のバックアップ設定
他の設定例として、リモートの dokku の home のバックアップ設定もしてみました。 設定が似ている vps-etc を雛形としてコピーして destination と source などを書き換える形で設定しました。
cd /etc/ccollect/sourcessudo cp -a vps-etc vps-home-
sudoedit vps-home/destinationで/srv/backup/vps-homeに変更 -
sudoedit vps-home/sourceでroot@vps.example.jp:/homeに変更 -
sudoedit vps-home/excludeで- cacheを追加 (/home/dokku/$APP/cache/は buildpack での build 時などのキャッシュに使われるのと、ファイルの所有者とグループがどんどん変わるので、バックアップからは除外)
初回バックアップ実行
vps-etc のバックアップと同様にバックアップ先ディレクトリを作成してからバックアップを実行します。
sudo mkdir -pv $(cat /etc/ccollect/sources/*/destination)sudo ~/src/github.com/ungleich/ccollect/ccollect daily vps-homesudo ~/src/github.com/ungleich/ccollect/ccollect daily vps-home
uid, gid 問題
LDAP などでアカウントを共通化していれば問題ないのですが、 rsync では uid や gid を数値のまま保存してコピーするので、バックアップ元とバックアップ先で同じ uid に対して別のユーザーが存在すると、意図しないユーザーが読めるバックアップができてしまうので、注意が必要です。
この記事の例だと /srv/backup/vps-home のパーミッションを変更する (sudo chmod 700 /srv/backup/vps-home) などの対処をしておくと良いと思います。
バックアップの差分の確認
ccollect.text の Comparing backups によると rsync -n -a --delete --stats --progress daily.20080324-0313.17841/ daily.20080325-0313.31148/ のように -n オプション付きで rsync を実行することによってバックアップの差分を確認できるようです。
まとめ
ccollect で差分バックアップを作成するようにしました。
rsync によるバックアップなので、圧縮などもするバックアップツールと違い、バックアップの内容も元のディレクトリ構造そのままでわかりやすいので、一部だけ復元するなどの操作も素直に実行しやすくなっています。
ハードリンクなので i-node は消費しますが、変化がないファイルについては容量を消費しないので、バックアップサイズも抑えられます。