unisonによる2台のサーバ間でのファイル同期
DRDBのようなリアルタイム同期を使うほどではないが、2台のLinuxサーバ間で一部のファイルを同期したいときがある。そのようなときに自分はunisonを使う。
unisonは非同期的にファイルを2台のサーバ間で同期するためのツールです。rsyncとは異なり、あらかじめ同期したいディレクトリやファイル名を設定ファイルに登録しておき、同期を必要とするときにunisonコマンドを実行すると2台のサーバ間で予め同期登録していたファイルが同期されるというセミオートマティックな仕組みが実現できます。
unisonのインストールは以下の手順で可能です。
yum install unison
sudo apt-get update && apt-get install unison
■ freeBSD
cd /usr/ports/net/unison/ && make install clean
unisonをインストールするときに注意が必要なのは、同期したいサーバ間のunisonのバージョンは必ず一致していなければいけないという点です。unisonのバージョンが一致してなければ同期に失敗してしまう。
同期したいファイルの設定方法ですが、unisonコマンドを実行するユーザーのホームディレクトリ上にunisonディレクトリを作成し、そのディレクトリ配下に設定ファイルを任意のファイル名で保存します。これはunisonコマンドを実行する側である一方のサーバ上のみに作成するだけでOKです。
■ ホームディレクトリ配下に.unisonディレクトリの作成
mkdir ~/.unison
例えば、2台のサーバ間で/etc/crontabを同期するための設定ファイルは以下のように登録できます。この設定ファイルのことをunisonのプロファイルと呼びます。プロファイルは複数個作成することもできます。
■ 設定ファイル例(~/.unison/crontab_sync.prf)
# コピー元ファイルのタイムスタンプも一緒にコピーする
times = true
# 新しいファイルを優先
prefer = newer
# ルート・ディレクトリの指定。同期の際に最上位となるディレクトリを設定する。
root = /etc/
root = ssh://server2//etc/
# 同期したいディレクトリやファイル名を指定する
path = crontab
# 無視するディレクトリやファイル名を指定する。
ignore = Name .*~
ここで注意したいのがunisonはデフォルト設定ではシンボリックリンクを同期しないという罠があります。シンボリックリンクも同期したい場合は、以下のような設定をプロファイルに追記する必要があります。
follow = Path ディレクトリ名 または ファイル名
同期したいファイルの登録が完了したらunisonコマンドを実行してみてください。unisonコマンドの実行書式は以下のようなフォーマットです。
■ 実行コマンド書式
Usage: unison [options]
or unison root1 root2 [options]
or unison profilename [options]
For a list of options, type "unison -help".
For a tutorial on basic usage, type "unison -doc tutorial".
For other documentation, type "unison -doc topics".
既にunisonのプロファイルを登録済みであれば、シンプルに以下のような書式で実行できる。
■ 実行例
unison <プロファイル名>
■ 初回同期実行時の実行結果
root@server1:~# unison crontab_sync
Contacting server...
root@server2's password:
Connected [//site-build//etc -> //unison//etc]
Looking for changes
Warning: No archive files were found for these roots, whose canonical names are:
/etc
//unison//etc
This can happen either
because this is the first time you have synchronized these roots,
or because you have upgraded Unison to a new version with a different
archive format.
Update detection may take a while on this run if the replicas are
large.
Unison will assume that the 'last synchronized state' of both replicas
was completely empty. This means that any files that are different
will be reported as conflicts, and any files that exist only on one
replica will be judged as new and propagated to the other replica.
If the two replicas are identical, then no changes will be reported.
If you see this message repeatedly, it may be because one of your machines
is getting its address from DHCP, which is causing its host name to change
between synchronizations. See the documentation for the UNISONLOCALHOSTNAME
environment variable for advice on how to correct this.
Donations to the Unison project are gratefully accepted:
http://www.cis.upenn.edu/~bcpierce/unison
Press return to continue.[<spc>] Waiting for changes from server
Reconciling changes
Nothing to do: replicas have been changed only in identical ways since last sync.
英語でずらずらと表示されるが、これはunison使用時の注意書きが説明されているだけなのでEnterキーで読み飛ばしても構いません。最終的に「Reconciling changes Nothing to do:」なので、このときは2台のサーバ間の対象ファイルに差分が存在せずに同期が完了したことを意味します。
■ 対向サイト上のファイルが更新されていた場合の実行結果
root@site-build:~# unison crontab_sync
Contacting server...
root@server1's password:
Connected [//site-build//etc -> //unison//etc]
Looking for changes
Waiting for changes from server
Reconciling changes
local unison
<---- changed crontab [f] <= ファイル名を確認し、更新してもよければenterキーを押す。
Proceed with propagating updates? ?
Commands:
y or g Yes: proceed with updates as selected above
n No: go through selections again
q exit unison without propagating any changes
Proceed with propagating updates? y <= 最終的にファイル更新しても問題なければyかgを押す。
Propagating updates
UNISON 2.40.65 started propagating changes at 06:39:46.95 on 29 Dec 2013
[BGN] Updating file crontab from //unison//etc to /etc
[END] Updating file crontab
UNISON 2.40.65 finished propagating changes at 06:39:46.95 on 29 Dec 2013
Saving synchronizer state
Synchronization complete at 06:39:46 (1 item transferred, 0 skipped, 0 failed)
■ 同期完了後の結果
root@server1:~# unison crontab_sync
Contacting server...
root@server2's password:
Connected [//site-build//etc -> //unison//etc]
Looking for changes
Waiting for changes from server
Reconciling changes
Nothing to do: replicas have not changed since last sync.
(最後にNothing to do: replicas have not changed since last sync.と表示されていれば、前回の最終同期以降に対象ファイルに差分は生じていないことを意味する。)
差分が発生しているファイルの同期確認に対話的に答えるのが面倒である場合や、cronで定期的にunisonによる同期を実行したい場合は-batchオプションを付けて実行すると非対話的に同期が実行されます。
■ 実行例
unison <プロファイル名> -batch
また、対向サーバのパスワードを毎回入力するのは面倒なので、対向サーバの~/.ssh/authorized_keysに公開鍵を登録しておくと良いです。
unisonの実践的な使い道としては、2台で筐体冗長されたサーバ間の設定ファイルやスクリプトの同期です。例えば、keepalivedでVRRP冗長しているサーバ同士のkeepalived.confの同期や、2台の監視サーバでの設定ファイルやスクリプトの同期、ローカルの開発環境からリモート上に存在するサーバへのファイル同期に利用するような使い方も考えられる。つまるところ、冒頭で書いたようにDRBDによるリアルタイムレプリケーションをしたいほどではないけれども、半自動化くらいはしたい場合などです。
unison単体ではファイルの世代管理まではやってくれないので、サービス提供向けの本格的な環境であれば別途gitなどを使った世代管理の必要性なども生じると思います。やや擬似的なリアルタイム同期をunisonで実現したい場合には、incronと組み合わせるのが良いと思います。incronはファイルの変更を検知したタイミングであらかじめ登録されたコマンドを実行するツールです。incorn単体での使い方は下記のサイトの記事が参考になります。
(個人的にはunison単体でセミオート的に使い続けることが多いです。設定ファイルやスクリプトの更新の際にしか使わないため、その更新頻度は年に数回あるかないか程度である場合がほとんどなのでセミオート的な運用でも使用に耐えてます。)
unisonはrsyncのアルゴリズムを採用しているようで、圧縮転送性能は貧弱なのでファイルサイズの大きいファイルの転送には全然向いてません。特にギガ単位の大きなサイズのファイルを転送する場合には、別途個別にlzopやpigzコマンドを利用して圧縮転送する方法を検討するのがベターだと思います。unisonコマンドのより詳細な使用方法については下記リンク先が参考になります。
以上のように、unisonの導入や取り扱いは比較的シンプルです。手動で毎回あらかじめ決まったディレクトリやファイルをサーバ間で同期しているような環境への導入をおすすめします。