前置き
現在性能試験で利用している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を取得して、リクエストの状況を監視します。
{
"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"
}
}
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参照)。
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登録
# 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設定
まずはアクティブになったリクエストのインスタンスIDを取得します。
INSTANCEID=$(aws ec2 describe-spot-instance-requests --filters Name=spot-instance-request-id,Values=${REQUESTID} --query SpotInstanceRequests[*].InstanceId --output text)
そのインスタンスをELBに登録します。
aws elb register-instances-with-load-balancer --load-balancer-name lbname --instances ${INSTANCEID}
まとめ
まとめるとこんな感じです。
引数は、落札価格 ドメイン名 ELB名です。
※ドメイン名.jsonでインスタンスプロパティーを設定しておいて下さい。
作成したいインスタンスタイプ毎に分けておくと便利かも。
# 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
監視サイクルは5秒、activeになるまでのタイムアウトは5分でやってます。
一時的なインスタンスを手ごろにコストダウンするのにいいですね。