ファイルの変更を検知して他のサーバーと同期する

こんにちは、コバヤシです。
今回は、ファイルの変更を検知して他のサーバーと同期する方法について書いていきます。

サーバーはAlmaLinux8を想定しています。

inotifywait

inotifywaitはLinuxシステムでファイルやディレクトリの変更を監視するためのコマンドラインツールです。 今回はファイル変更の監視としてinotifywaitを使用します。

dnf install -y inotify-tools

inotifywaitをインストールします。

rsynce

rsyncはファイルやディレクトリをリモートとローカルの間で同期するためのコマンドラインツールです。 同期に使用します。AlmaLinux8にはデフォルトで入っています。

同期用のバッチファイルを作成する

まずは、同期をするためのバッチファイルを作成します。 複数サーバーに同期する想定です。

#!/bin/bash

# 同期するディレクトリ
SYNCE_DIR="/var/www/public"
# 同期対象のサーバーリスト
SERVERS=("サーバー1" "サーバー2")
# SSH秘密鍵のパス
SSH_KEY="xxxxxxx.pem"
# 同期先のディレクトリ
DEST_DIR="/var/www/public"
# 除外リストファイル
EXCLUDE_FILE="exclude.txt"
  
for SERVER in "${SERVERS[@]}"; do
  rsync -az --delete --checksum -e "ssh -i $SSH_KEY" --exclude-from="$EXCLUDE_FILE" "$SYNCE_DIR" "xxxxxx@$SERVER:$DEST_DIR"
done

synce.shとして作成し実行権限を付与します。

オプションの説明です。

  • -a(archive): アーカイブモードで同期を行い、ディレクトリ、ファイルの属性(パーミッション、所有者、タイムスタンプなど)を保持します。
  • -z(compress): データを圧縮して転送します。
  • --delete:同期元に存在しないファイルを目的地から削除する
  • -e:リモートシェルを指定するオプションです。今回は、SSHを使用して暗号化キーによる接続を指定しています。
  • --exclude-from:同期をしないファイルやディレクトリを別のファイルで指定します。今回はexclude.txtを作成し除外したいファイル名やディレクトリを記述しています。

監視用のバッチファイルを作成する

監視をするためのバッチファイルを作成します。

変更があったファイルの数だけrsyncが実行されてしまうため、フラグを作成し、フラグがあったら実行中と判断して処理を行わないようにしています。 また、複数ファイルの更新に対応するために60秒後に同期を行うようにsleepを入れています。

#!/bin/bash

# 監視するディレクトリ
WATCHED_DIR="/var/www/public"
# フラグファイルのパス
FLAG_FILE="/tmp/rsync_in_progress.flag"
# 同期スクリプトのパス
SYNC_SCRIPT="synce.sh"

inotifywait -m -r -e modify,create,delete --format '%w%f' --exclude '^/var/www/public/xxxx/' "$WATCHED_DIR" | while read change
do
  # フラグファイルが存在し、かつ30分以上前に作成されている場合、削除する
  if [ -f "$FLAG_FILE" ]; then
    if [ "$(date +%s -r "$FLAG_FILE")" -le $(( $(date +%s) - 1800 )) ]; then
      rm "$FLAG_FILE"
    fi
  fi

  # フラグファイルが存在しない場合のみ同期処理を実行
  if [ ! -f "$FLAG_FILE" ]; then
    touch "$FLAG_FILE"
    
    sleep 60

    # 同期スクリプトの実行
    bash "$SYNC_SCRIPT"
    rm "$FLAG_FILE"
  fi
done

inotifywait.shとして作成し実行権限を付与します。

オプションの説明です。

  • -m:モニターモードで実行します。イベントが発生するたびに終了せずに監視を続けます。
  • -e modify,create,delete:監視するイベントの種類を指定します。
    • modify:ファイルが変更されたときに通知します。
    • create:新しいファイルやディレクトリが作成されたときに通知します。
    • delete:ファイルやディレクトリが削除されたときに通知します。
  • --format '%w%f':ファイルやディレクトリのパスを出力フォーマットを指定します。%wはイベントが発生したディレクトリのパス、%fはイベントが発生したファイル名です。
  • --exclude:特定のファイルやディレクトリを監視から除外するために使用します。正規表現で指定します。

サービスに登録する

作成したバッチ処理をサービスとして登録して常時監視・同期できるようにします。

/etc/systemd/system/sync-service.service

[Unit]
Description=Sync Service

[Service]
ExecStart=/パス/inotifywait.sh
Restart=always

[Install]
WantedBy=multi-user.target

サービスの起動と常時起動をします。

systemctl enable sync-service.service
systemctl start sync-service.service

これで、完了です。 /var/www/public/以下に何らかの更新があると別サーバーと同期されるようになります。

まとめ

この後、多少の調整は必要とはなりますが、
inotifywaitとrsyncを使うと比較的簡単に目的の処理を実現できました。
たまにはプログラミング以外のことをやってみると楽しいものです。
これからも新しいことにチャレンジして技術の幅を広げていきたいです。