AWSのElastic BeanstalkにRailsプロジェクトをおいていて、非同期のジョブをSidekiqにやらせている。
で、原因は色々とあるようだがたまにsidekiqプロセスが居なくなることがあった。
取り急ぎ、止まっていたら起動するように2つの方針を考えた。
- monitでモニタリング&restart
- Upstartでrespawn
- inspeqtorでモニタリング
EBのRuby(puma)コンテナではRails用のpumaがUpstartで動いている。
monit(+M/Monit)の柔軟設定とゆるさは鉄板だが(飽きてきたので)、ここはsidekiqの作者Mike Perhamさんのプロダクトであるinspeqtorと組み合わせてみよう。パーハム祭りである。
参考: Inspeqtor - application infrastructure monitoring
SidekiqをUpstart配下にする
まずは 『Sidekiq x Upstart』。
設置したファイルは3つです。Upstart用のファイルはほぼEBのpumaから流用。
/opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_sidekiq
/opt/elasticbeanstalk/hooks/appdeploy/pre/03_mute_sidekiq
-
/opt/elasticbeanstalk/support/conf/sidekiq.conf
(/etc/init/sidekiq.conf
にシンボリックリンク作成)
まず必要なファイルを設置。
pumaのコンフィグで特に参考になったのはexec /bin/bash <<"EOT"
。その手があったかー。
Sidekiqの起動オプションはお好みで。muteは一応。
---
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_sidekiq":
mode: "000755"
content: |
#!/bin/bash
initctl restart sidekiq || initctl start sidekiq
ln -sf /var/app/current/log/sidekiq.log /var/app/containerfiles/logs/sidekiq.log
"/opt/elasticbeanstalk/hooks/appdeploy/pre/03_mute_sidekiq":
mode: "000755"
content: |
#!/bin/bash
. /opt/elasticbeanstalk/support/envvars
PIDFILE=/var/app/containerfiles/pids/sidekiq.pid
if [ -f ${PIDFILE} ]; then
if [ -d /proc/`cat ${PIDFILE}` ]; then
kill -USR1 `cat ${PIDFILE}`
fi
fi
"/opt/elasticbeanstalk/support/conf/sidekiq.conf":
mode: "000644"
content: |
description "Elastic Beanstalk Sidekiq Upstart Manager"
start on runlevel [2345]
stop on runlevel [!2345]
# explained above
respawn
respawn limit 3 30
script
# scripts run in /bin/sh by default
# respawn as bash so we can source in rbenv
exec /bin/bash <<"EOT"
EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
. $EB_SUPPORT_DIR/envvars
. $EB_SCRIPT_DIR/use-app-ruby.sh
EB_APP_DEPLOY_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
EB_APP_PID_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_pid_dir)
cd $EB_APP_DEPLOY_DIR
exec su -s /bin/bash -c "sidekiq -e ${RACK_ENV} -c ${SIDEKIQ_WORKERS:-2} -L ${EB_APP_DEPLOY_DIR}/log/sidekiq.log -C ${EB_APP_DEPLOY_DIR}/config/sidekiq.yml -P ${EB_APP_PID_DIR}/sidekiq.pid" webapp
EOT
end script
pumaの真似をしてリンク作成、initcrlをリロード。
---
files:
"/etc/init/sidekiq.conf" :
mode: "120400"
content: "/opt/elasticbeanstalk/support/conf/sidekiq.conf"
commands:
reload_initctl_for_sidekiq:
command: "initctl reload-configuration"
これでeb deployすればsidekiqがUpstart配下で起動する。
SidekiqがUpstart配下にあることを確認する
一応見に行こう。
$ sudo initctl status sidekiq
sidekiq start/running, process 22745
killしてもリスポーンすることもついでに確認しておくとよいかも。
inspeqtorをElsticBeanstalkのRubyコンテナに導入する
リポジトリを登録して、yumからインストール。
ここは別ファイルにしないとpackagesが先に実行されるみたい。
---
commands:
01_download_inspeqtor_repo_register:
command: "/usr/bin/curl -L https://bit.ly/InspeqtorRPM -o /tmp/InspeqtorRPM"
02_setup_inspeqtor_repo:
command: "/bin/bash /tmp/InspeqtorRPM"
---
packages:
yum:
nc: []
inspeqtor: []
このrpmはインストール後に自動でinspeqtorが起動する。操作はinitctlで。
SidekiqをInspectorでモニタリングする
次は『sidekiq x inspector』。
ファイルを置いてinspeqtorをリスタートしよう。
---
files:
"/etc/inspeqtor/services.d/sidekiq.inq":
content: |
check service sidekiq
if memory:rss > 500m then restart
if cpu:user > 60% for 2 cycles then restart
commands:
reload_inspeqtor:
command: "initctl restart inspeqtor || initctl start inspeqtor"
メール通知の行き先は適当に。自分はこういうのはPagerdutyに送る。
InspectorがSidekiqの状態を見ていることを確認。
inspeqtorctl
で状況を確認できる。
$ sudo inspeqtorctl status
Inspeqtor 0.8.1, uptime: 47m47.786741131s, pid: 3685
Host: ip-xx-xx-xx-xx
cpu 0.8%
cpu:iowait 0.1%
cpu:steal 0.1%
cpu:system 0.2%
cpu:user 0.5%
disk:/ 50.0% 90%
load:1 0.00
load:15 0.05
load:5 0.01 10
swap 1.0% 20%
Service: sidekiq [Up/22745]
cpu:system 0.0%
cpu:total_system 0.0%
cpu:total_user 0.0%
cpu:user 0.0% 60%
memory:rss 1.42m 500m
よし見てるね。これで仕様は次の通り。
- 止まってたらリスタート
- よーわからん高負荷だったらリスタート(アラート)
ほか
Sidekiq::Stats
なデータはカスタムメトリクスでClowdWatchに送るなりもOK。
ついでにNew RericとAirBrakeも使っている。
Sidekiq用のRedisはアプリ間で共有が必須かどうかなどの要件に応じて、Redis To Go、ローカルRedis(epelからさくっと入れることができる)、ElastiCache から選ぶといい。