スポットインスタンスの強制終了前に割り込み処理を入れる

EC2のスポットインスタンスは安くて大変お買い得ですが、価格が上がると強制ターミネートされるのがにんともかんとも。きちんとサービスアウトできる余裕が必要なので以下のようなスクリプトを書いて終了時にsleepするようにしてみたのですが、二通目のメールは届かず…

#!/bin/bash
# chkconfig: - 99 00

start()
{
  touch /var/lock/subsys/notify-stopped
}

stop()
{
  date | mail foo@example.com
  sleep 15
  date | mail foo@example.com
}

restart()
{
  stop
  start
}

case "$1" in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  restart
  ;;
*)
  echo "Usage: $0 {start|stop|restart}"
  ;;
esac

exit 0

いったんターミネートが始まると、さすがに速攻で殺されるようでした。

価格上昇とターミネート開始までのタイムラグ

いろいろと調べてみたところ、現在の価格がMaxPriceを超えてから実際のターミネートが開始されるまで一分程度のタイムラグがあるようでした。一分も余裕があれば自分でサービスアウトするのに十分な時間です。そこで数秒おきに価格をポーリングし現在の価格がMaxPriceを超えた時に特定の処理を行うスクリプト群を書いてみました。

autognosis
autognosis is a tool which processes when EC2 Spot Instance is terminated compulsorily.

インストール

※現在はサーバクライアント型になりました

スポットインスタンス激戦区のus-east-1にテスト用のインスタンスをセットアップ。スポットインスタンスの起動時には「{"maxPrice":0.3}」のようなJSON形式のuser-dataを仕込みます。


sudo yum install mailx -y
wget https://bitbucket.org/winebarrel/cronexec.spec/downloads/cronexec-0.90-1.amzn1.x86_64.rpm
wget https://bitbucket.org/winebarrel/jq.spec/downloads/jq-1.2-1.amzn1.x86_64.rpm
wget https://bitbucket.org/winebarrel/describe-spot-price-history/downloads/describe-spot-price-history-0.1.2-1.noarch.rpm
wget https://bitbucket.org/winebarrel/autognosis/downloads/autognosis-0.1.4-1.amzn1.noarch.rpm
sudo rpm -ihv *.rpm

sudo vi /etc/sysconfig/autognosis
sudo initctl start autognosis

/etc/sysconfig/autognosisは以下の通り。

# AWS Credential
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

# expected json: {"maxPrice":0.3}
MAX_PRICE=`curl -s 169.254.169.254/latest/user-data | jq '.maxPrice'`

#CHECK_INTERVAL=5

ON_TERMINATE='echo detected termination: `curl 169.254.169.254/latest/meta-data/instance-id` `date` | mail -s "detected termination: $(curl 169.254.169.254/latest/meta-data/instance-id) $(date)" foo@example.com'

#EXECUTE_ONCE=1
#EXEC_FLAG_FILE=/var/tmp/autognosis.executed


また、価格上昇と実際にインスタンスが停止するまでのタイムラグを計るため、終了処理開始時にメールを送るようにします。


sudo vi /etc/init.d/notify-stopped
sudo chmod 755 /etc/init.d/notify-stopped
sudo chkconfig --add notify-stopped
sudo chkconfig notify-stopped on
sudo touch /var/lock/subsys/notify-stopped
#sudo /sbin/shutdown -r now

終了スクリプト(/etc/init.d/notify-stopped)は前述のものと同様。

#!/bin/bash
# chkconfig: - 99 00

start()
{
  touch /var/lock/subsys/notify-stopped
}

stop()
{
  INSTANCE_ID=`curl 169.254.169.254/latest/meta-data/instance-id`
  DATE=`date`
  echo stopped: $INSTANCE_ID $DATE | mail -s "stopped: $INSTANCE_ID $DATE" foo@example.com
}

restart()
{
  stop
  start
}

case "$1" in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  restart
  ;;
*)
  echo "Usage: $0 {start|stop|restart}"
  ;;
esac

exit 0

結果

スポットインスタンスを立ち上げて、強制的にターミネートされるまで待った結果が以下の通り。


  • stopped: i-42815632 Sun Jan 27 17:41:05 UTC 2013
  • stopped: i-44815634 Sun Jan 27 17:41:05 UTC 2013
  • detected termination: i-44815634 Sun Jan 27 17:40:09 UTC 2013
  • detected termination: i-42815632 Sun Jan 27 17:40:06 UTC 2013
  • stopped: i-645b8f14 Sun Jan 27 16:59:21 UTC 2013
  • detected termination: i-645b8f14 Sun Jan 27 16:58:22 UTC 2013

おおむね一分程度のタイムラグです。

補足

us-east-1以外のリージョンではテストしていないので、もしかしたら差異があるかもしれないです。というかus-east-1以外は平和すぎてテストが長引くんですよね…。
また、公式の情報ではないので今後も一分のタイムラグが続くかは不明です。


安全な終了処理が出来ないのは結構痛いので、Amazon側でなんらかの機能を出してほしいところではあります。