Ubuntu Server ２台間でファイル同期(lsyncd + rsync + sshd)

# 背景
２台のLinuxサーバーでファイル同期させて冗長化やバックアップに利用するメモです。

# 動作環境

- OS:Ubuntu Server 16.04LTS
- OS:Ubuntu Server 18.04LTS
- sshd
- rsync
- lsyncd

# 同期設定のポリシー
２台のサーバー間を双方向で同期する方法と、バックアップの様に片側同期する方法があります。
今回は後者の片側同期に設定します。
双方向同期の場合はファイル削除時の動作を設計時に考慮しないと思わぬデータ消失に繋がり注意が必要です。

# rsyncサービスデーモン(rsyncd)
ネットで検索するとrsyncdを使用するページが出てきますが、その場合はサービスポートTCP 873番を経由します。
しかし昔ながらのIPアドレス範囲をallow/denyで制限したり、暗号化無しの平文パスワード利用と今時のセキュリティ的にはよくありません。
閉域網のセキュリティが確保された内部のサブネットで、転送速度のパフォーマンス重視の場合などで検討しましょう。今回は使用しません。

rsyncコマンドをsshd経由で暗号化して公開鍵認証した安全な経路が利用できますので、外部のインターネット経由したサーバー間でも安全な同期が可能です。
sshサービスデーモン(sshd)経由を利用するので一般的なsshd設定が利用可能です。

# sshユーザー設定
各サーバーに適当なアカウント「rsync」を作成します。
ユーザーアカウントでシステムファイル操作のパーミッション権限はsudoで対応します。

```:各サーバー共通
$ sudo adduser rsync
```

sudoグループに追加します。

```:各サーバー共通
$ sudo gpasswd -a rsync sudo
```

「rsync」ユーザーに切り替えてパスフレーズ無しのssh鍵ペアを作成します。
コメントの-Cオプションにサーバーホスト名も付けておくと区別し易いね。

```:サーバー１(node1)側
$ su rsync
$ ssh-keygen -t ed25519 -C "rsync@node1" -N ""
```

```:サーバー２(node2)側
$ su rsync
$ ssh-keygen -t ed25519 -C "rsync@node2" -N ""
```

ssh鍵を互いのサーバーへ登録します。
方法は色々ありますがssh-copy-idコマンドが簡単。

```:サーバー１(node1)側
$ ssh-copy-id -i .ssh/id_ed25519 rsync@node2
```

```:サーバー２(node2)側
$ ssh-copy-id -i .ssh/id_ed25519 rsync@node1
```

実際にパスフレーズ無しの公開鍵認証で接続出来るか、互いのサーバーで確認します。

```:サーバー１(node1)側
$ ssh -i .ssh/id_ed25519 rsync@node2
```

```:サーバー２(node2)側
$ ssh -i .ssh/id_ed25519 rsync@node1
```

rsyncコマンドをsudo経由でパスワード入力無しで実行する設定(サーバー２ node2側)

```:サーバー２(node2)側
$ sudo visudo
```

```:/etc/sudoers
rsync ALL=(ALL) NOPASSWD: /usr/bin/rsync
```

パスフレーズ無しのssh鍵であってもsudoコマンド実行時にはアカウントのパスワード入力を要求されますので、特定コマンド(この場合はrsync)だけパスワード要求を無効化します。
これでrsyncコマンドをsudo経由で実行出来るので、ファイルの書き換え時にパーミッション制限でのエラーを回避出来ます。

# lsyncサービスデーモン(lsyncd)設定

同期元サーバー１(node1)側へインストールして設定する。ちなみに双方向で同期する場合は両方へインストールします。

```:サーバー１(node1)側
$ sudo apt-get install lsyncd
```

設定ファイルを作成します。
サンプルファイルが、「/usr/share/doc/lsyncd/examples/lsyncd.conf.lua」とかにありますので参考に。

```:/etc/lsyncd/lsyncd.conf.lua
settings = {
        logfile = "/var/log/lsyncd.log",
        statusFile = "/tmp/lsyncd.stat",
        insist = 1,
        statusInterval = 10
}

sync_base = {
        default.rsync,
        delete = running,
        init = false,
        rsync = {
          archive = true,
          rsync_path = "sudo /usr/bin/rsync",
          rsh = "/usr/bin/ssh -i /home/rsync/.ssh/id_ed25519 -o StrictHostKeyChecking=no"
        }
}

sync{ sync_base, source="/home/rsync/test1/", target="rsync@node2:/home/rsync/test1/"}
sync{ sync_base, source="/etc/test2/", target="rsync@node2:/etc/test2/"}
```
設定オプションは以下の様になります。

- statusInterval：インターバル・デフォルト10秒
- delete = running：同期時のみ削除可
- init = false：起動時は同期を反映しない
- archive = true：rsyncの-aオプションと同等
- rsync_path = "sudo /usr/bin/rsync"：rsyncコマンドをsudo経由で実行

最後のsyncの２行で監視するディレクトリと同期先を２箇所指定しています。複数ある場合は同じ様に追加設定します。

## lsyncサービスデーモン(lsyncd)の再起動

```:サーバー１(node1)側
$ sudo systemctl restart lsyncd
```

## 動作確認
適当な空ファイルを作成して、サーバー２(node2)側に反映するか確認してみます。

```:サーバー１(node1)側
$ touch /home/rsync/test1/test1.txt
```

```:サーバー２(node2)側
$ ls -l /home/rsync/test1/
```

sudo経由なのでシステムファイルも同期出来ます。

```:サーバー１(node1)側
$ sudo touch /etc/test2/test2.txt
```

```:サーバー２(node2)側
$ ls -l /etc/test2/
```


動作検証にログファイルが確認出来ます。

```:サーバー１(node1)側
$ sudo tail /var/log/lsyncd.log
```