CentOSにおけるファイル同期(lsyncd+rsync)

Date:

Share post:

特定のディレクトリ配下(サブディレクトリ含む)のファイル群を別マシンの特定ディレクトリ配下にコピーしたいことがあります。
目的はバックアップであったりある種のデプロイであったり。
2つのディレクトリに関する同期としてはrsyncコマンドで簡単に実現できますが、いちいち手作業で同期するのは面倒ですし、特別な仕掛けを自製したりせずに随時発生する更新結果をリアルタイム性高く同期させる方法はないものかと思って調べたところ意外に呆気なくその方法が見つかりましたので、今回はその方法を紹介したいと思います。
具体的には、同期自体にはやはりrsyncを使用しますが、更新に対する(ほぼ)リアルタイムでの自動同期実行にlsyncdを使用するという方法です。

なお、今回の実装環境は以下になります。
【同期元】
OS : CentOS7.9.2009
IP : 192.168.33.22
ユーザー : rsyncmaster
ディレクトリ : /home/rsyncmaster/share
【同期先】
OS : CentOS7.9.2009
IP : 192.168.33.23
ユーザー : rsyncslave
ディレクトリ : /home/rsyncslave/share

rsync環境構築

まずはrsyncが実行できる環境を整えます。
同期元のユーザー「rsyncmaster」で以下のコマンドを実行し、rsync時の認証に必要な鍵のペアを作成します。

ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa.rsync

「-N」(パスフレーズ指定)には空文字を指定。
もし当該ユーザーのホーム配下に「.ssh」ディレクトリがなければ事前に作成しておく必要がありますが、パーミッションを「0700」にしておくことを忘れずに(この辺に関しては厳しくチェックされているようで、適性なパーミッションにしておかないと以降の操作がエラーになります)。
これで「~/.ssh」配下に「id_rsa.rsync」(秘密鍵)と「id_rsa.rsync.pub」(公開鍵)が生成されます。

公開鍵は同期先ユーザー「rsyncslave」の「~/.ssh/authorized_keys」に反映します。
「authorized_keys」は同ユーザーが認識する公開鍵を列記したもので、複数の公開鍵を含むファイルです。
よって、既に「authorized_keys」が存在すればその末尾に先に作成した「id_rsa.rsync.pub」の内容を追加し、存在しなければ「id_rsa.rsync.pub」をそのまま「~/.ssh/authorized_keys」としてコピーすれば良いです。
なお、この際も「.ssh」のパーミッションは「0700」に、「authorized_keys」のパーミッションは「0600」に設定することを忘れずに。

上記ができたら、同期元ユーザー「rsyncmaster」で同期先ユーザー「rsyncslave」にssh接続できることを確認します。

ssh -i ~/.ssh/id_rsa.rsync rsyncslave@192.168.33.23

今までの設定に問題がなければ上記操作で同期先マシンに「rsyncslave」でログインできるはずです。

上記まで問題なければ、最後にrsyncとしての動作確認を行っておきます。
今回同期の対象と考えている同期元ディレクトリ「/home/rsyncmaster/share」と同期先ディレクトリ「/home/rsyncslave/share」を作成し、同期元ディレクトリ配下に適当なファイルを作成して以下のようにrsyncコマンドを実行します。

rsync -av -e "ssh -i ~/.ssh/id_rsa.rsync" ~/share/ rsyncslave@192.168.33.23:/home/rsyncslave/share

同期先ディレクトリ配下に同期元で作成したファイルが配置されていればOKです。
これで、何らかの方法でrsyncを実行できれば同期元ディレクトリの内容を同期先ディレクトリに反映できる状態になりました。

lsyncdインストール

同期元の更新状態を監視し、(ほぼ)リアルタイムにrsyncを実行するための仕組み「lsyncd」の環境構築を行います。
まずはインストールから。
お手軽にyumを使ってインストールできますが、EPELリポジトリを追加しておく必要があります。
以降は同期元マシンのrootユーザーで実施します。

yum install epel-release

上記結果としてEPELリポジトリが常に有効な状態になってしまっているので、特に指定した場合のみ有効になるように設定を書き換えておきます。

sed -i -e "s/enabled=1/enabled=0/" /etc/yum.repos.d/epel.repo

上記は本手順の手本とさせていただいたサイトの流儀をそのまま反映したものですが、sedを用いなくてもvi等で直接書き換える方法でもOKです。

上記でEPELリポジトリが使用できるようになりましたので、これを指定しつつyumで「lsyncd」をインストールします。

yum --enablerepo=epel install -y lsyncd

lsyncd環境設定

lsyncdがインストールできたら設定ファイル「/etc/lsyncd.conf」に必要な設定内容を記述します。
具体的な内容は以下の通り。

settings {
  logfile = "/var/log/lsyncd/lsyncd.log",
  statusFile = "/var/log/lsyncd/lsyncd.status",
  insist = 1
}

sync{
  default.rsync,
  source = "/home/rsyncmaster/share/",
  target = "rsyncslave@192.168.33.23:/home/rsyncslave/share/",
  delete = true,
  delay = 1,
  rsync = {
    archive = true,
    compress = true,
    rsh = "/usr/bin/ssh -i /home/rsyncmaster/.ssh/id_rsa.rsync -o UserKnownHostsFile=/home/rsyncmaster/.ssh/known_hosts"
  }
}

「settings」はlsyncdの挙動全体に関わる設定、「sync」は期待される同期に関わる設定で、「sync」の方は同期内容に合わせて複数記述できる模様。詳しくは「https://axkibe.github.io/lsyncd/」を参照してください(要英語力)。
「logfile」は文字通りログ情報を残すファイルパスの指定です。「statusFile」の方は定期的にステータスのレポートを記録するものらしいですが、そもそもステータスが何であるかがあまり分かっておらず(先輩方の情報に準じてとりあえず設定)。
「insist」はマシン起動時に同期先への接続ができなくてもリトライを続けると言う指定で、これを指定しておかないと同期先マシンが落ちている状態で同期元マシンを先に起動し、後から同期先マシンを起動した場合は同期が行われなくなってしまいます。蛇足ながら、ログを見ると本リトライは3秒周期で行われている模様で間隔的にも良い感じかと。
lsyncdとしては複数の同期方法を持っているようですが、最も基本的と思われるrsyncを用いることを示す設定が「default.rsync」のようです。
「source」「target」はそれぞれ「同期元」「同期先」を示す情報ですが、この辺はrsyncの実行イメージから理解可能かと。
「delete」は同期元でファイル/ディレクトリが削除された場合にその結果を同期先に反映するかどうかの指定で、これもrsync自体にある想定なので理解はできますね。ただ、設定内容としてはlsyncd独自の流儀もあるようで、細かく使いこなしたいのであれば前述のサイトの内容を確認してもらうのが良いかと。上記例ではシンプルに同期元で削除されたものは同期先でも削除する設定になっています。
「delay」は同期元環境下における更新監視周期(秒)らしく、短くすればそれだけリアルタイム性が上がるということのようです。ただ、この辺は更新頻度・量によってはシステムに与える負荷が大きくなりそうなことは想像できますし、適宜調整すべきかと思います。
「rsync」では文字通りrsync実行時に指定すべきその他パラメータの設定ができます。
個人的にはrsync実行時にはオプションとして「-avz」を愛用していますが、「-v」は動作内容の表示指定なので自動実行時には不要であるため、「-az」に相当する「archive」「compress」(いずれもデフォルトはfalse)をtrueにしておきます(それぞれのオプションの意味はGoogle先生に聞いてください)。ただし、既に圧縮されたファイルを多く含む場合、圧縮指定「compress」しても無駄な処理が実行されるだけで逆に処理効率が落ちます(動画のみを対象としたケースでは圧縮指定した方が3倍近い時間がかかっていました)。よって対象ファイルがどのような形式かも考慮してオプションの指定方法を吟味する必要がありそうです。
「rsh」では主としてssh接続時に使用する秘密鍵の在処を指定しています(なお同オプション内の指定で「-o」以降がなぜ必要なのか疑問ではありますが、ないとエラーになります)。

lsyncd起動

上記設定ができたら、lsyncdを起動します。

systemctl start lsyncd

特にエラーが出なければOKです。
ただ、上記は単にlsyncdを起動しただけで、マシン再起動時などには逐一起動操作が必要になります。
よって、マシン起動時にlsyncdが自動的に起動されるように設定しておきます。

systemctl enable lsyncd

動作確認

同期元ディレクトリに適当にファイルやディレクトリを追加、変更、削除して、同期先ディレクトリにその内容が(ほぼ)リアルタイムに反映されることが確認できればOKです。

蛇足ながら、しばしば「(ほぼ)リアルタイムに」と表現しているのは当然ながら「リアルタイム」ではないからでして、具体的には以下の2つのタイムラグがあります。

  • lsyncdが更新を察知するまでの時間(delay値に依存)
  • rsyncにおけるファイルIOや通信に要する時間

後者は対象データの数や量に依存して大きくなりますが、これはファイル管理および通信の仕組み上避けがたい時間です。
前者に関しても、特定のディレクトリ配下に変化があった場合にファイルシステム側から能動的にその旨を通知してくれるような仕組みがあれば別ですが、そうでなければ(ファイルシステム外の仕組みとして変化を察知しようとすれば)定期的にチェックを行うという方法にしかならないでしょうし、「定期的」となればその間隔が「遅れ」になることは止むを得ないかと。
と言うことで、ベストではないにしてもそれに近いベターなレベルのリアルタイム性を持った同期方式と判断し、「(ほぼ)リアルタイム」の称号を与えたいと思います。

先にも触れましたがlsyncdとしては設定ファイル「/etc/lsyncd.conf」での調整の余地もありそうなので、より効率の良い同期が行えるよう今後も調査・検討して行きたいと思いますが、今回はここまで。

Related articles

EC-CUBE 4系のプラグイン開発について その...

前回、プラグインを一旦有効化させて管理...

EC-CUBE 4系のプラグイン開発について その...

以前から作成したいと考えていたのですが...

Laravel Filamentを使用した管理画面...

前回Breezeをインストールしたこと...

Laravel Filamentを使用した管理画面...

前回、filamentでのリソース作成...