lsyncd でファイル変更監視して、S3にアップロードする

WordPress のメディアファイルを自動でバックアップしたり、CloudFront のオリジンにするために wp-content/uploads/ の中身を S3 にアップロードするようにしたいなぁとか言う要望が結構あります。
特に AutoScaling 構成にする場合は、ソースファイルについては git リポジトリなどで管理すればいいですが、ダッシュボードからアップロードされるメディアファイルについては git リポジトリに含めるわけに行かないっすよね。
そんな時、僕の作ったプラグイン絡新婦とか、Amazon S3 for WordPress with CloudFrontとか使うわけですが、なんと 4.3.x 系ではちゃんと動かないような気がするんです

まぁ、僕が絡新婦をメンテナンスすればいいのですが、最近 php プログラム書くの辛いので代替手段として lsyncd でファイル変更を監視して S3 に自動アップロードするようにしてみました。
参考URL: lsyncdをrsync以外の用途で使う – Qiita

まず、lsyncd をインストールします。
網元なら、以下のコマンドでインストール可能です。

$ sudo rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
$ sudo yum install lsyncd

次に lsyncd 設定ファイル( /etc/lsyncd.conf )を作成します。こんな感じです。

settings {
  logfile = "/var/log/lsyncd/lsyncd.log",
  nodaemon = false,
}

exec = function(event)
  local src_path = event.sourcePathname
  spawnShell(event, "/bin/sh /home/ec2-user/bin/s3-uploads " .. src_path .. " || :" );
end

s3_media_upload = {
  maxProcesses = 1,
  delay = 0,
  onCreate = exec,
  onDelete = exec,
  onMove = exec,
}

sync {
  s3_media_upload,
  source = "/var/www/vhosts/{instance ID}/wp-content/uploads",
}

何をやってるかというと

settings {} ではログファイルの位置、デーモンモードでの起動 ( nodaemon = false ) を設定しています。

exec = function(event) では、lsyncd で変更が検知された時に実際に起動するコマンドを指定してます。
event.sourcePathname には、変更が検知されたファイルのパスがセットされます。
lsyncd では、spawnShell で呼び出されたコマンドが error を返す( リターンコード0以外 )と lsyncd 自体が終了しちゃうので、後ろに "|| :" つけて、必ず 0 を返すようにしてます。

s3_media_upload = {} では、ファイルが作成された時( onCreate )、削除された時( onDelete )、移動された時( onMove )に実行するコマンドを指定しています。

sync {} では、監視対象のディレクトリ( source )と、変更が検知された時に呼ばれる設定セット( s3_media_upload )を設定しています。

あとは、exec の中で呼ばれる /home/ec2-user/bin/s3-uploads というシェルスクリプトを作っておきましょう。
こんな感じ

#!/bin/sh
s3_bucket='static.example.com'
region='ap-northeast-1'
aws="/usr/bin/aws --region=${region}"

if [ "${1}" = "" ]; then
  ${aws} s3 sync /var/www/vhosts/{instance ID}/wp-content/uploads/ s3://${s3_bucket}/wp-content/uploads/

else
  target_path="${1}"
  string_filename=${target_path##*/}
  string_path=${target_path%/*}
  s3_path="${string_filename}"
  while [ "${string_filename}" != "wp-content" ]; do
    string_filename=${string_path##*/}
    string_path=${string_path%/*}
    if [ "${string_filename}" != "" ]; then
      s3_path="${string_filename}/$s3_path"
    fi
  done
  if [ -f ${target_path} ]; then
    ${aws} s3 cp ${target_path} s3://${s3_bucket}/${s3_path}
  else
    ${aws} s3 rm s3://${s3_bucket}/${s3_path}
  fi
fi

引数無しで呼ばれた場合は wp-content/uploads/ 全体を sync
引数ありで呼ばれてファイルが存在する場合には s3 cp コマンドでアップロード
引数アリで呼ばれてファイルが存在しない場合には s3 rm コマンドで s3 バケットから対象ファイルを削除

します。

S3 へのアップロード権限を設定する必要があるのでインスタンス作成するときに IAM ロールで権限を与えておくか、IAM ユーザー作って aws configure で設定しておかないとですね。

lsyncd を起動する前にこのコマンドを引数無しで実行して、現在の wp-content/uploads/ の中身を全部 S3 バケットに転送しておくと良いですね。

ここまで出来たら "sudo service lsyncd" で lsyncd を起動させてやればおっけ。

コメントを残す

メールアドレスが公開されることはありません。