@uzyexe のノート

ITインフラ運用系のネタを主に書く、つもり・・・

unisonによる2台のサーバ間でのファイル同期

DRDBのようなリアルタイム同期を使うほどではないが、2台のLinuxサーバ間で一部のファイルを同期したいときがある。そのようなときに自分はunisonを使う。

 

unisonは非同期的にファイルを2台のサーバ間で同期するためのツールです。rsyncとは異なり、あらかじめ同期したいディレクトリやファイル名を設定ファイルに登録しておき、同期を必要とするときにunisonコマンドを実行すると2台のサーバ間で予め同期登録していたファイルが同期されるというセミオートマティックな仕組みが実現できます。

f:id:uzy_exe:20131231234332p:plain

 

unisonのインストールは以下の手順で可能です。

RHEL/CentOS

yum install unison

debian/Ubuntu

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台で筐体冗長されたサーバ間の設定ファイルやスクリプトの同期です。例えば、keepalivedVRRP冗長しているサーバ同士のkeepalived.confの同期や、2台の監視サーバでの設定ファイルやスクリプトの同期、ローカルの開発環境からリモート上に存在するサーバへのファイル同期に利用するような使い方も考えられる。つまるところ、冒頭で書いたようにDRBDによるリアルタイムレプリケーションをしたいほどではないけれども、半自動化くらいはしたい場合などです。

 

unison単体ではファイルの世代管理まではやってくれないので、サービス提供向けの本格的な環境であれば別途gitなどを使った世代管理の必要性なども生じると思います。やや擬似的なリアルタイム同期をunisonで実現したい場合には、incronと組み合わせるのが良いと思います。incronはファイルの変更を検知したタイミングであらかじめ登録されたコマンドを実行するツールです。incorn単体での使い方は下記のサイトの記事が参考になります。

(個人的にはunison単体でセミオート的に使い続けることが多いです。設定ファイルやスクリプトの更新の際にしか使わないため、その更新頻度は年に数回あるかないか程度である場合がほとんどなのでセミオート的な運用でも使用に耐えてます。)

 

unisonはrsyncアルゴリズムを採用しているようで、圧縮転送性能は貧弱なのでファイルサイズの大きいファイルの転送には全然向いてません。特にギガ単位の大きなサイズのファイルを転送する場合には、別途個別にlzopやpigzコマンドを利用して圧縮転送する方法を検討するのがベターだと思います。unisonコマンドのより詳細な使用方法については下記リンク先が参考になります。

 

以上のように、unisonの導入や取り扱いは比較的シンプルです。手動で毎回あらかじめ決まったディレクトリやファイルをサーバ間で同期しているような環境への導入をおすすめします。