[AWS]lsyncdでEC2のディレクトリとS3を同期する[Linux]

lsyncd_ec2_s3

ある日、エルシンク使ったことある?と先輩に尋ねられた。
(エルシンク。バンドみたいな名前だな。)
俺は言った。
聞いたことすらないんですけどなんか面白そうですね。

先輩はこれやってみて。rsyncではなくlsyncやから。
俺は言われるがまま仕様を渡された。

仕様をざっくり説明すると以下の構成になる。

オンプレのサーバ -> EC2 -> S3

オンプレのサーバからデータをEC2のサーバにsftpでアップロードしたときにS3にコピーする。

なるほどそんなことが出来るのかと感心した。

やったことないけどとにかく面白そうといえばチームの間は良好。
ただ自分は地獄をみる。

まずエルシンクとはからはじまる。

Google神にお尋ね
rsyncがめちゃくちゃ出る。

rsyncじゃないと先輩が言っていたような。

lsyncd とはこれだ。

lsyncd(Live Syncing Daemon)はリアルタイムのファイル同期を提供する仕組みのひとつです。inotifyというファイルの変更を検知すると、rsyncd経由で同期先のサーバへファイルを転送します。このページでは、lsyncd, rsyncdの使い方についてまとめます。
lsyncd rsyndの設定方法

リアルタイム同期するための無料ソフトのようだ。

lsyncdはかなり痛い目にあったオープンソースなので、正直お勧めできません。とは言っても、lsyncdを運用せざるを得ない残念な方もいらっしゃると思いますので、そんな残念なOpsのためにまとめ記事を書きます。

おすすめじゃないと書いてある。きちんと検索しないと出てこない部分とか下火感は否めない。
ただ、地雷原に入ってしまったらもう後戻りは出来ない鉄の心臓を用いて突き進んで行くしかない。

実装は以下のように行った。

nodeaemonはエラーになったのでコメントアウトしている。
lsyncdはLua言語で書かれている。
Lua言語のコメントアウトは–で行う。


# cat /etc/lsyncd.conf
settings{
        logfile = "/var/log/lsyncd/s3_lsyncd.log",
        statusFile = "/var/log/lsyncd/s3_upload.stat",
        statusInterval = 5,
--        nodeaemon = false,
}

exec = function(event)
    local src_path = event.sourcePathname
    spawnShell(event, "/bin/bash /opt/lsyncd/s3_upload.sh " .. src_path .. " || :" );
end

s3_upload = {
    maxProcesses = 2,
    delay = 0,
    onCreate = exec,
    onDelete = exec,
    onMove = exec,
}

sync {
    s3_upload,
    source = "/opt/s3_src_dir",
}

内部でロードされるスクリプト

S3へのコピーと削除はaws cliコマンドを用いている。


#cat /opt/lsyncd/s3_upload.sh
#!/bin/bash

# aws s3バケット名
S3_BUCKET_NAME='hogehoge-s3'

# 送信元のファイルパスを設定
SRC_PATH="${1}"

# ログ出力ファイル
LOGDIR="/var/log/lsyncd/"

# ログ出力ファイル
LOGFILE="/var/log/lsyncd/lsyncd_s3.log"

################################################################################

# ログ出力ファイル存在確認(なければ作成)
if [ ! -e $LOGDIR ]; then
    mkdir -p $LOGDIR
fi
if [ ! -e $LOGFILE ]; then
    touch $LOGFILE
fi

# ログ出力
readonly PROCNAME=${0##*/}
function log() {
    local fname=${BASH_SOURCE[1]##*/}
    echo -e "$(date '+%Y-%m-%dT%H:%M:%S') ${PROCNAME} (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $@" | tee -a ${LOGFILE}
}

################################################################################

# リトライ処理
retry() {
    MAX_RETRY=5
    n=0
    until [ $n -ge $MAX_RETRY ]
    do
        "$@" && break
        n=$[$n+1]
        sleep $[ ( $RANDOM % 15 )  + 1 ]s
    done
    if [ $n -ge $MAX_RETRY ]; then
        log "ERROR: ${@}" >&2
        exit 1
    fi
}

################################################################################

# 送信元ファイルパスから不要な部分をカットして送信先用に使う. 例として17に設定している.
DST_PATH=`echo ${SRC_PATH} | cut -c 17-`
if [ -f ${SRC_PATH} ]; then
    # excludeオプションを使って, 更新検知から除外したいファイルを指定する. includeオプションも一緒に設定しないとexcludeが効かないので要注意.
    retry aws s3 cp ${SRC_PATH} s3://${S3_BUCKET_NAME}${DST_PATH} --include "*" --exclude "*.log"
    log "copy${SRC_PATH} s3://${S3_BUCKET_NAME}${DST_PATH}"
else
    # ファイルが削除されたら, s3側も同じように削除されるように設定する.
    retry aws s3 rm s3://${S3_BUCKET_NAME}${DST_PATH}
    log "rm${S3_BUCKET_NAME}${DST_PATH}"
fi

################################################################################

やったことなかったがなんとかなってよかった。

上記のスクリプトの作成にあたり参考にしたサイトを列挙する。

参考:lsyncdで更新ファイルを検知してaws s3へファイルアップロード

参考:シェルスクリプトのロギングを楽にするtips

参考:シェルスクリプトでリトライ処理を追加する

シェアよろしくお願いします!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です