1日の中のトラフィックの変動に合わせてEC2の起動台数を増減させる方法

JAWS-UG Advent Calendar 2013 4日目の投稿です
昨日は@j3tm0t0さんのg2インスタンスを使って宇宙へ行こう!です

11/2の第9回JAWS-UG大阪で発表したときにはManualScalingとして紹介した方法の解説

ゲームに限らず、アクセス数の多いブログやニュースサイトなんかでは、例えばお昼の12時からの1時間のほうが、その前後の1時間に比べて数倍のトラフィックがくることがよくありますよね

1日のピーク値にあわせてサーバを用意しておくというのはイマイチ「クラウド」っぽくありません
そこで、毎日のトラフィックの増減の予想から、指定時間でサーバを起動させる仕組みを作ってみました

なお、指定時刻でサーバを増減させる仕組みを、AWSのドキュメントではScheduled Scalingっていうらしいです。AutoScalingのコマンドで実現可能です。
詳しくはこちら

この公式のScheduled Scalingは、既に運用面も含めてAutoScaling構成になっている環境では簡単に使えるのですが、今回はあえてAutoScalingを使わない方法をご紹介します

今回ご紹介する方法には、コチラのようなメリットがあります

・サーバ減少時にTerminateではなくStop状態でサーバを保存しておける。ログ消えない
・サーバ増加時にはStop状態のサーバをStartさせる。インスタンスの作成時間を短縮
・最新プログラムをサーバへダウンロードするときは前回Stop時からの差分のみなのでわりと高速
・最新プログラムの反映を待ってからELBにサーバを組み込む

ということで、まずは全サーバに次のような起動スクリプトを仕掛けます

#!/bin/bash
#
# Auto associate Elastic IP , rsync and register ELB
#
# chkconfig: 345 98 6
# description: rsync and register ELB
# processname: rsync-elb
#
export JAVA_HOME=/usr/lib/jvm/jre
export EC2_HOME=/opt/aws/apitools/ec2
export AWS_ELB_HOME=/opt/aws/apitools/elb

# 初期化
RSYNC_SERVER=""
ELB_SERVER=""

# 自分のインスタンスIDを取得
INSTANCE_ID=$(/usr/bin/curl http://169.254.169.254/latest/meta-data/instance-id)

# インスタンスIDを元にtagを取得
TAGS=`/opt/aws/apitools/ec2/bin/ec2-describe-tags -O アクセスキー -W シークレットキー --filter "resource-id=${INSTANCE_ID}"  --region ap-northeast-1|/usr/bin/awk '{print $4,$5}'`

# スペース区切りでtagが返ってくるので配列へ
ARR_TAGS=(`echo $TAGS`)

# tagのキーとバリューが交互に入っているのでループ
for i in `seq 1 ${#ARR_TAGS[@]}`
do
  if [[ 'rsync' == ${ARR_TAGS[$i-1]} ]];then
    RSYNC_SERVER=${ARR_TAGS[$i]}
  fi
  if [[ 'elb' == ${ARR_TAGS[$i-1]} ]];then
    ELB_SERVER=${ARR_TAGS[$i]}
  fi
#  キーとバリューが交互なので1つ飛ばす
  i=`expr $i + 1`
done

if [[ $RSYNC_SERVER != "" && $ELB_SERVER != "" ]]; then
#   rsync実行
  /usr/bin/sudo -u ユーザー /usr/bin/rsync -av --update -e "/usr/bin/ssh -i /home/ユーザー/.ssh/秘密鍵 -o \"StrictHostKeyChecking no\"" --include="いろいろ" --exclude="*"  "${RSYNC_SERVER}:/コピー元ディレクトリ"  /コピー先ディレクトリ
  if [ $? -eq 0 ]; then
#   rsync成功 ELB登録
    /opt/aws/apitools/elb/bin/elb-register-instances-with-lb  ${ELB_SERVER} --instances ${INSTANCE_ID} -O アクセスキー -W シークレットキー  --region ap-northeast-1
    if [ $? -eq 0 ]; then
#      ELB登録成功 Apache起動
      /etc/init.d/httpd start
    fi
  else
#   失敗はシャットダウン
    /sbin/shutdown -h now
  fi
else
# 失敗はシャットダウン
  /sbin/shutdown -h now
fi

ttyがない状態でもsudoが使えるように下記の修正


# visudo
コメントアウト
#Defaults    requiretty

そして、次のようなマネージメントコンソールからタグを仕掛けます
scaling

rsync:rsync先のサーバのPublicDNS
elb:elbのLoad Balancer Name

次に指定時間に増減させたいインスタンスIDを指定した起動・停止用スクリプトを作成します

起動用スクリプト

vi /home/ec2-user/EC2-server-start.sh 
------------------------------------------------------------------------------
#!/bin/sh
/opt/aws/bin/ec2-start-instances  -O アクセスキー -W シークレットキー  --region ap-northeast-1 i-XXXXXXXX i-YYYYYYYY
------------------------------------------------------------------------------
chmod +x  EC2-server-start.sh

停止用スクリプト

vi /home/ec2-user/EC2-server-stop.sh
------------------------------------------------------------------------------
#!/bin/sh
# ELB切り離し
elb-deregister-instances-from-lb ELBの名前 --instances  i-XXXXXXXX,i-YYYYYYYY  -O アクセスキー -W シークレットキー   --region ap-northeast-1

# ELB切り離し後、30秒ほど時間を空ける
sleep 30

# インスタンス停止
/opt/aws/bin/ec2-stop-instances -O アクセスキー -W シークレットキー  --region ap-northeast-1 i-XXXXXXXX i-YYYYYYYY
------------------------------------------------------------------------------
chmod +x  EC2-server-stop.sh

最後にお好みの起動・停止時間をcronで設定して終わり

明日は@ar1さんです。