【AWS】CliでSpotInstanceを作成＆Route53とELB登録


# 前置き
現在性能試験で利用しているEC2の料金が高いことから、スポットインスタンスを検討することになりました。
条件として

- PrivateIpを固定
- 異なるAMIからそれぞれのEC2をローンチ
- 同じELBを利用

があるため、ちょっとめんどくさかったのでメモします。


# インスタンス作成リクエスト
spot-instanse-request

>参考:http://docs.aws.amazon.com/cli/latest/reference/ec2/request-spot-instances.html

スポットインスタンス作成のリクエストを発行します。
リクエスト発行前にインスタンスのattibuteを設定したjsonを用意しておいて下さい。
リクエスト時に返却されるJsonからリクエストIDを取得して、リクエストの状況を監視します。


```instance.json
{
  "ImageId": "ami-12345679",
  "InstanceType": "m3.large",
  "KeyName": "key-name",
  "NetworkInterfaces": [
    {
      "SubnetId": "subnet-12345678",
      "DeviceIndex": 0,
      "PrivateIpAddress": "123.45.67.890",
      "Groups": [
        "sg-12345678"
      ]
    }
  ],
  "IamInstanceProfile": {
      "Name": "iam-name"
  }
}
```

```request-sopt.sh
REQUESTID=$(aws ec2 request-spot-instances --spot-price "0.01" --instance-count 1 --type "one-time" --launch-specification file://instance.json --query SpotInstanceRequests[*].SpotInstanceRequestId --output text)
```


# 状況監視
describe-spot-instance

>参考:http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/spot-requests.html

リクエストの状況を監視します（ステータスの移行ルールに関しては上記参考URL参照）。

```check-status.sh
while :
do
  STATE=$(aws ec2 describe-spot-instance-requests --filters Name=spot-instance-request-id,Values=${REQUESTID} --query SpotInstanceRequests[*].State --output text)
  echo ${STATE}
  if [ -z ${STATE} ]; then
    sleep 5s
  elif [ ${STATE} = "active" ]; then
    break
  elif [ ${STATE} = "failed" ]; then
    exit 1
  else
    sleep 5s
  fi
done
```

ステータスがactiveになった時点でELBへの登録を行います。

# Route53登録

>参考:http://qiita.com/3utama/items/5a0211e6bad7380b8a27


```
# Get Public Dns
PUBLICDNS=$(aws ec2 describe-instances --region ap-northeast-1 --instance-ids ${INSTANCEID} --query Reservations[*].Instances[*].PublicDnsName --output text)

if [ -z ${PUBLICDNS} ]; then                                                                                                                                          # Get Private IP
  PRIVATEIP=$(aws ec2 describe-instances --region ap-northeast-1 --instance-ids ${INSTANCEID} --query Reservations[*].Instances[*].PrivateIpAddress --output text)
  # Create Route53 A Reocrd
  sudo cli53 rrcreate hosted_zone $3 A ${PRIVATEIP} --replace --ttl 60
else
  # Create Route53 CNAME Reocrd
  sudo cli53 rrcreate hosted_zone $3 CNAME ${PUBLICDNS} --replace --ttl 60
fi
```

# ELB設定

>参考:http://docs.aws.amazon.com/ja_jp/ElasticLoadBalancing/latest/DeveloperGuide/elb-deregister-register-instances.html#deregister-instances-cli

まずはアクティブになったリクエストのインスタンスIDを取得します。

```get-instance-id.sh
INSTANCEID=$(aws ec2 describe-spot-instance-requests --filters Name=spot-instance-request-id,Values=${REQUESTID} --query SpotInstanceRequests[*].InstanceId --output text)
```

そのインスタンスをELBに登録します。

```regist-lb.sh
aws elb register-instances-with-load-balancer --load-balancer-name lbname --instances ${INSTANCEID}
```

# まとめ
まとめるとこんな感じです。

引数は、落札価格 ドメイン名 ELB名です。
※ドメイン名.jsonでインスタンスプロパティーを設定しておいて下さい。
　作成したいインスタンスタイプ毎に分けておくと便利かも。

```request-spot-elb.sh
# Spot Instance Request
REQUESTID=$(aws ec2 request-spot-instances --spot-price "$1" --instance-count 1 --type "one-time" --launch-specification file://$2.json --query SpotInstanceRequests[*].SpotInstanceRequestId --output text)

# Check Status
while :
do
  STATE=$(aws ec2 describe-spot-instance-requests --filters Name=spot-instance-request-id,Values=${REQUESTID} --query SpotInstanceRequests[*].State --output text)
  echo ${STATE}
  if [ -z ${STATE} ]; then
    sleep 10s
  elif [ ${STATE} = "active" ]; then
    break
  elif [ ${STATE} = "failed" ]; then
    exit 1
  else
    sleep 5s
  fi
done
if [ $? -eq 1 ];then
  exit 1
fi

# Get Instance Id 
INSTANCEID=$(aws ec2 describe-spot-instance-requests --filters Name=spot-instance-request-id,Values=${REQUESTID} --query SpotInstanceRequests[*].InstanceId --output text)

# Get Public Dns
PUBLICDNS=$(aws ec2 describe-instances --region ap-northeast-1 --instance-ids ${INSTANCEID} --query Reservations[*].Instances[*].PublicDnsName --output text)
if [ -z ${PUBLICDNS} ]; then                                                                                                                                          # Get Private IP
  PRIVATEIP=$(aws ec2 describe-instances --region ap-northeast-1 --instance-ids ${INSTANCEID} --query Reservations[*].Instances[*].PrivateIpAddress --output text)
  # Create Route53 A Reocrd
  sudo cli53 rrcreate hosted_zone $3 A ${PRIVATEIP} --replace --ttl 60
else
  # Create Route53 CNAME Reocrd
  sudo cli53 rrcreate hosted_zone $3 CNAME ${PUBLICDNS} --replace --ttl 60
fi

# Regist ELB
if [ -n "$4" ]; then
  aws elb register-instances-with-load-balancer --load-balancer-name $3 --instances ${INSTANCEID}
fi
```


監視サイクルは５秒、activeになるまでのタイムアウトは5分でやってます。
一時的なインスタンスを手ごろにコストダウンするのにいいですね。