元々OpenSUSEが入っていたAblenetのVPSを、さくらのVPSのバックアップ機として使うためUbuntuに入れ替え、rsyncで自動バックアップをとるようにしてみました。
SSHの鍵を変更したくない場合はバックアップしておく。
まぁ、/etc
以下と/usr/local/etc
以下を丸ごとバックアップしておくのがよいのではないだろうか。
とりあえずインストールメディアでブートする必要がある。
Ubuntuのサイトから Downloads → Alternative Downloads → Download the network installer for 18.04 LTS → amd64 と進んで、ubuntu-installer/amd64
からlinux
とinitrd.gz
をダウンロードする。
あとはGRUBを設定してブートする。
さくらのUbuntuメディアは必要な設定がほぼすべて、あらかじめ設定された状態でインストールされるようになっているが、今回は一般のインストールメディアなので、若干手順が違う。
C
を選んでおく。
admin
とかsetup
とかはSSHで執拗にアタックを受けるので避けるべき。
/home
はフォーマットしないで作業してたんだけど、途中でrm -rf
しちった。
Unattended Upgrade
の設定を確認しておく。
hwclock --debug
で分かる。
初回ブート後にも少し作業が必要。
GRUB_CMDLINE_LINUX="ipv6.disable=1 video=800x600" GRUB_TIMEOUT=5
update-grub2
を忘れないように。
sshd
が入ってないので、ここでインストール
$ sudo apt install openssh-server
あとは正サーバーと同じように設定していくのだが、正サーバーでは/usr/local/etc
をgitで管理しているので、まずはこれをcloneしてしまう。
/usr/local/etc/.git
のパーミッションに注意。
root:wheel 750 g+s
とかにしておくのが無難。
cloneしたらブランチを作って、バックアップサーバー(副サーバー)にのみ適用する変更を加える。
実際の運用では修正→コミット→fetch→マージ、という手順になるが、マージには方向性があるので気をつける。 つまり、今の例では正サーバーのリポジトリを副サーバーにcloneして、副サーバー用の変更を加えているから、正サーバー側で副サーバーの変更をマージすると、副サーバー用の変更が全部適用されてしまう。 この例では、正サーバーから副サーバー向きはマージ、副サーバーから正サーバーにはcherry-pickになる。
副サーバーで設定の変更をテストして、それを正サーバーにも適用する場合、色々方法はあるが、面倒でも副サーバー側で作業ブランチを作り、そこに変更をコミットして、正サーバーでfetchしたあと、副サーバーのメインブランチから作業ブランチへの差分をcherry-pick、副サーバーに戻ってメインブランチに切り替えて、正サーバーの変更をfetchしてマージするのがいいと思う。 作業が終わったら作業ブランチは消してしまう。
正サーバー専用の変更がある場合は、副サーバーにマージしてしまって、コミットをrevertするのがいいと思う。 こうしておけば正サーバー側はブランチを切らずに作業できる。 こういうルールを決めておかないと、あとでマージがにっちもさっちもいかなくなる。 まぁ全部cherry-pickで運用するのが一番安全かもしれない。
マージ・cherry-pickを行う場合、普通は一度ローカルにブランチをチェックアウトすると思うが、実はその必要はない。
git merge origin/master
のようにすれば、リモートのブランチをいきなりマージすることができる。
正サーバー用のローカルブランチは消してしまってかまわない。
混乱の元なのでむしろ消してしまったほうがよい。
というのは、ローカルブランチにチェックアウトしてマージする場合、マージが必要ない限り副サーバー上で正サーバー用のブランチをチェックアウトすることはないから、マージ作業がないと副サーバー上の正サーバー用ローカルブランチはちょっと古いものになる。
これを他の機械でcloneすると中途半端な正サーバーのブランチをcloneしてしまう。
ローカルブランチを消してしまっても、pushするときにpruneしてしまわなければ問題ない。
というか、fetchで運用するので基本的にpushしないし、正サーバーでは正サーバー用のブランチがチェックアウトされた状態になっているから、pruneできないはず。
お互いfetchしあうことでバックアップの代わりにもなる。 なお、ローカルブランチを作らない(clone後に消す)運用をしている場合、clone時にはローカルブランチしかcloneされないため、副サーバーからさらにcloneしたリポジトリには正サーバーのブランチはリモートブランチとしてすら存在しないことに注意。 正サーバーのブランチが欲しければ、正サーバーからもcloneする必要がある。
設定を変更しないといけないのは主にMTAだと思われる。
転送専用の設定(virtualdomains
を削除、locals
を空ににし、必要に応じてsmtproutes
を設定)にする。
あと、基本的にユーザーディレクトリがないので、Webサーバーの設定も少し変える必要がある。
DNSはそのうち書こうと思っているLet's EncryptのACMEチャレンジゾーン以外は全部同じ設定で大丈夫。
というか、少なくともゾーンファイルは同じにしなければならない。
先に結論。
rsync最強。
要点は、--link-dest
オプションでハードリンクを使って差分バックアップすることと、fake superを使うこと。
ハードリンクを使うと、ディレクトリツリーを丸々構成したまま、変更のないファイルにはハードリンクを張るので、データの実体はひとつだけになる。
100個ファイルがあり、90個は更新がなく、10個は更新された場合、ディレクトリツリーとしては100個のファイル×2バージョン分が見えるが、実体としては元の100個+更新された分の10個、合計110個分だけしかディスク容量を消費しない。
また、途中のバックアップが不要になったら、そのディレクトリだけrm -rf
してしまえばよい。
たとえば、1月1日から毎日バックアップをとり続け、2月になったら1月分を全部消したとする。
この場合、1月3日に作成したファイルを1月29日に消したような場合はさすがに残らないが、2月までそのファイルが残っていれば、1月分を消してしまっても問題ない(リンクカウントが1になってちゃんと残る)。
ちなみに新しくバックアップされたファイルはfind . -links 1
で分かる。
fake superを使うと、バックアップ先にroot
でログインしなくてよくなる。
バックアップ元ではすべてのファイルを読む必要があるから、バックアップはroot
権限で実行する必要がある。
それを書き込む先でディレクトリツリーをユーザーIDも含めて再構成しようとすると、バックアップ先でもroot
権限が必要になる。
しかし、sshでroot
ログインを禁止しているから、ログインしてからスーパーユーザーになる必要があるが、パスワードで困ってしまう。
fake superではバックアップ先のログインユーザーでファイルを作成し、ファイルの拡張属性にアクセス権の情報を格納する。
拡張属性はattr -g rsync.%stat filename
とすると得られる。
具体的な作業はこんな感じ。
bkuphost
とする)でバックアップ作業用のユーザーを作る。仮にbkupuser
とする。
mainhost
とする)のroot
でssh用の鍵を作る。パスフレーズは空にする。管理には気をつける。
bkupuser
ユーザーの~/.ssh/authorized_keys
に書く。
command="rsync --server --daemon .",restrict public-key-spec...と書いて、
rsync
の実行以外できないようにする。
このコマンドはどうやって調べたかというと、とりあえずauthorized_keys
に
command="echo $SSH_ORIGINAL_COMMAND > rsync.command" public-key-spec...と書いてリモートから
rsync
を適当に実行してみると、rsync.command
にサーバーで実行しようとしていたコマンドが出力されるので、これをそのまま書き込む。
rsync
を起動した場合、サーバー側の設定はログインしたユーザーのホームディレクトリから読み込まれるので、以下のような内容のrsync.conf
をbkupuser
のホームディレクトリに置く。
use chroot = false read only = false write only = true fake super = true hosts deny = * [mainhost] path = /home/bkupuser/mainhost hosts allow = mainhost.example.jp
/home/bkupuser/mainhost
ディレクトリを作っておく。
パーミッションに注意。
rsync --rsh="ssh -i privkeyfile -l bkupuser" -azH fromdir/ bkuphost::mainhost/todir
とするとバックアップが走る。
あとはcron
で定期的に実行すればよいが、mainhost
側でこんなスクリプトを実行している。
#!/bin/bash : ${user:=bkupuser} : ${host:=bkuphost} : ${module:=mainhost} : ${sshkey:=~/.ssh/keyprefix-${host}} : ${prevfiledir:=/var/rsync-backup} : ${prevfilename:=prior-dir} : ${prevfile:=${prevfiledir}/${prevfilename}} : ${ssh:=ssh} : ${sshcmd:=$ssh -i $sshkey -l $user} : ${rsync:=rsync} : ${rsyncopt:=--bwlimit=1M} destdir=$(date +%Y%m%d) rsynclinkdest="" if [ -f ${prevfile} ]; then if [ "$(cat ${prevfile})" != "/${destdir}" ]; then rsynclinkdest="--link-dest=$(cat ${prevfile})" fi fi # create parent directory in the target host $rsync --rsh="$sshcmd" $rsyncopt . $host::$module/$destdir/ while read from to; do if [ ! -z "$rsynclinkdest" ]; then linkdest=$rsynclinkdest/$to fi $rsync --rsh="$sshcmd" -azH $rsyncopt $linkdest $from $host::$module/$destdir/$to done echo "/$destdir" > $prevfile
このスクリプトは
/home/bkupuser/mainhost/20190523/etcのようなディレクトリにバックアップすることを想定している。
rsynclinkdest
変数は差分バックアップが可能ならば--link-dest
オプションが設定される。
初回バックアップ時は空になる。
バックアップに成功すると/var/rsync-backup/prior-dir
にバックアップ先のディレクトリ名が書き込まれ、次回バックアップ時にこのファイルの内容が--link-dest
としてrsynclinkdest
変数に設定される。
最終的に転送先のサブディレクトリが追加されてrsyncのオプションに指定される。
rsyncはこのディレクトリを基準に転送対象のファイルを比較し、変更がなければハードリンクで済ませる。
つまり、ハードリンクによる差分バックアップを行う。
次に一度rsync
コマンドを実行しているが、これは中間ディレクトリ(20190523
の部分)を作成している。
rsyncは中間部分のディレクトリは作ってくれないが、末端のディレクトリは作ってくれるらしく、こうするとディレクトリだけ作ってくれるらしい。
mkdir -p
に相当するオプションはないのかな?
見落としてるだけな気もするけど。
while read ...
からがバックアップ本体。
標準入力から1行にバックアップ元ディレクトリ、バックアップ先ディレクトリを書いたファイルを突っ込む。
たとえば、
/etc/ etc /usr/local/etc/ usr.local.etcのように書く。 これで
/usr/local/etc
はモジュールで指定されたディレクトリの20190523/usr.local.etc
以下にバックアップされる。
バックアップ元の最後にスラッシュをつける必要がある。
付けないと20190523/usr.local.etc/etc
にバックアップしようとする。
-a
はアーカイブ、-z
は圧縮転送、-H
はハードリンクをハードリンクとして転送。
rsyncopt
変数に設定してある--bwlimit=1M
は転送レートをバイト/秒単位で指定している。
module
変数に設定してある値は、先のrsyncの設定ファイルで[mainhost]
と書いてある部分に対応する。
実際の転送先や、アクセスを許すホストなどが設定してある。
最後に今回のバックアップ先ディレクトリを/var/rsync-backup/prior-dir
に記録しておく。
これで次回から差分バックアップが走る。
Copyright (C) 2019-2020 akamoz.jp
$Id: backup-server.htm,v 1.6 2020/02/06 16:06:27 you Exp $