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/intervals
echo 10 | sudo tee /etc/ccollect/defaults/intervals/daily
echo 24 | sudo tee /etc/ccollect/defaults/intervals/monthly
echo 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)-home
echo '/home' | sudo tee /etc/ccollect/sources/$(hostname)-home/source
echo "/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/exclude
echo '- *~' | 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/summary
sudo 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)-home
sudo ~/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-etc
echo /srv/backup/vps-etc | sudo tee /etc/ccollect/sources/vps-etc/destination
echo root@vps.example.jp:/etc | sudo tee /etc/ccollect/sources/vps-etc/source
echo '- *.swp' | sudo tee -a /etc/ccollect/sources/vps-etc/exclude
echo '- *~' | sudo tee -a /etc/ccollect/sources/vps-etc/exclude
sudo touch /etc/ccollect/sources/vps-etc/summary
ネットワーク的につながらない時はバックアップが失敗するので、事前チェックするようにします。
sudoedit /etc/ccollect/sources/vps-etc/pre_exec
sudo 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-etc
sudo ~/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/intervals
echo 10 > ~/.config/ccollect/defaults/intervals/daily
echo 24 > ~/.config/ccollect/defaults/intervals/monthly
echo 10 > ~/.config/ccollect/defaults/intervals/weekly
mkdir -p ~/.config/ccollect/sources/vps-srv
echo /srv/backup/vps-srv > ~/.config/ccollect/sources/vps-srv/destination
echo vpsuser@vps.example.jp:/srv > ~/.config/ccollect/sources/vps-srv/source
echo '- *.swp' > ~/.config/ccollect/sources/vps-srv/exclude
echo '- *~' >> ~/.config/ccollect/sources/vps-srv/exclude
touch ~/.config/ccollect/sources/vps-srv/summary
ネットワーク的につながらない時はバックアップが失敗するので、事前チェックするようにします。
editor ~/.config/ccollect/sources/vps-srv/pre_exec
chmod +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-srv
env CCOLLECT_CONF=$HOME/.config/ccollect ~/src/github.com/ungleich/ccollect/ccollect daily vps-srv
env 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-ccollect
sudo 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/sources
sudo 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-home
sudo ~/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 は消費しますが、変化がないファイルについては容量を消費しないので、バックアップサイズも抑えられます。