EC-CUBE3とAuto ScalingしたEC2とlsyncd+rsyncd

EC-CUBE3のコンテンツ同期

やりたいこと

EC-CUBE3をEC2に構築しているが、管理機能とユーザー機能でインスタンスを分けているので、管理機能からページ更新などの更新処理が行われたら、ユーザー機能のEC2に更新したコンテンツを反映したい。

構成

EC2の構成は以下の通り。すべてのEC2インスタンスには、同じEC-CUBE3をインストールしている。したがってEC-CUBE3の構成は全く同じ。

  1. 管理機能:EC2x1台
  2. ユーザー機能:EC2xN台(Auto ScalingでN台まで増える。初期は2台)

問題はユーザー機能がAuto Scaringしているところ。EC2が台数固定であれば、lsyncd+rsyncdで単純に同期を取れば済むのだが、Auto Scaringの場合は台数が増えたことを検知しなければいけないし、IPが動的に変わってしまうのでそのあたりも考慮しないといけない。

解決策

lsyncdがLuaの記法でスクリプト書けるので、あとはAWS CLIを駆使して対象となるEC2の情報を取得、動的にコンテンツ配布先を指定して同期するように処理を組めば良い。
aws.amazon.com

EC2のIPを取得するShell

事前に、EC2のIP一覧を取得するShellを作っておくと良い。これをlsyncd.confから呼び出す。
使用するコマンドは「aws ec2 describe-instances」。ただしこれだけだとIPアドレスのみ抽出はできない。以下は参考程度のコマンド例だが、filterオプションなどを使ってAuto ScaringしているEC2インスタンスを絞り込む必要がある。

#!/usr/bin/env bash
REGION=us-west-1
aws ec2 describe-instances --region ${REGION} --filter "Name=instance-state-name,Values=running" --query "Reservations[*].Instances[*].NetworkInterfaces[*].PrivateIpAddresses[*].[PrivateIpAddress]" --output text | sort

スクリプトを実行すると、以下のようにIPが一覧表示されるのが望ましい。

10.0.10.100
10.0.10.101
10.0.10.102

/etc/lsyncd.conf に設定を書く

Lua記法を駆使して同期設定を書く。以下の記事を参考にした。
qiita.com
qiita.com
ひとつひとつ説明していくと長くなるので、作ったlsyncd.confを少し手直しして公開する。

----
-- User configuration file for lsyncd.
--
-- Simple example for default rsync, but executing moves through on the target.
--
-- For more examples, see /usr/share/doc/lsyncd*/examples/
--
--sync{default.rsyncssh, source="/var/www/html", host="localhost", targetdir="/tmp/htmlcopy/"}
settings {
    logfile    = "/var/log/lsyncd/lsyncd.log",
    statusFile = "/tmp/lsyncd.stat",
    statusInterval = 1,
}

function get_instance_list()
    local command='/path/to/script'
    local commandResult = exec(command)
    local result = string.gsub(commandResult, "\n", " ")
    return  split(result, " ")
end

function split(str, delim)
    assert(str,  "文字列が設定されていません")
    assert(delim,"区切り文字がしていされていません")
    local pattern = "[^"..delim.."]*"..delim

    local result = {}
    for item in string.gmatch(str, pattern) do
        local tmp = item:gsub(delim,"")
        table.insert(result, tmp)
    end
    return result
end

function exec(command)
    local handle = io.popen(command,"r")
    local content = handle:read("*all")
    handle:close()
    return content
end

-- Set lsyncd target files.
lsyncd_target_dirs = {
    rsync_test1="/path/to/rsync_test1",
    rsync_test2="/path/to/rsync_test2",
    rsync_test3="/path/to/rsync_test3"
}

lsyncd_target_hosts = get_instance_list()

for lsyncd_target_host_key, lsyncd_target_host in pairs(lsyncd_target_hosts) do
    for lsyncd_target_dir_key, lsyncd_target_dir in pairs(lsyncd_target_dirs) do
        sync{
            default.rsync,
            source=lsyncd_target_dir,
            target=lsyncd_target_host .. "::" .. lsyncd_target_dir_key,
            delay = 0,
            rsync = {
                _extra = {"-av","--delete"}
            }
        }
    end
end

配布先インスタンスのrsyncdの設定は割愛。lsyncdとrsyncdを利用した同期設定については特別なことをする必要はないので、他の記事を参考にするとよい。また同期を行うパスについては、ご自身のサイト構成にあわせて設定を書く必要がある。ちなみにユーザー機能側のEC2インスタンス上に作成されるtwigのキャッシュは、同期するときに必ず削除するようにしたほうがよい*1

よくわかっていない問題

lsyncdが変更を検知してtiwgキャッシュを削除してくれないことがある。なぜこういう事象が発生するか調べきれなかったので、cronで定期的にlsyncdを再起動して回避している。

*1:--deleteオプション使うと良い