aws-cliでスポットリクエストをスポット群リクエストでスポットインスタンスの立ち上げからダウンまでやってみる



aws-cliを使い始めた初心者がチョコチョコ叩きながら試してようやくできた。。。。
結構ハマったけども結論からいうと色々ハマって色々学べたから結果良しとしよう。という前向きな気持ちになれた。


## 参考にしたサイト

* [【新機能】AWS CLIがアップデート！新機能「EC2 Spot Fleet API」が超便利！](http://dev.classmethod.jp/cloud/aws/introduce-to-ec2-spot-fleet-api/)
* [AWS スポットインスタンスリクエスト](http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/spot-requests.html)
* [AWS スポット群リクエスト](http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/spot-fleet-requests.html)

## 環境

* CentOS 6.7
	* aws-cli 
		* aws-cli/1.10.1 Python/2.7.10 Linux/2.6.32-573.el6.x86_64 botocore/1.3.23



## 【注意事項】スポットインスタンスリクエストとスポット群リクエストは違うよ!!!

自分はこれでハマりました。

説明が合っているかどうかはわからないけれども、

* スポットインスタンスリクエスト(spot-instance-requests)は元々あった旧形式(色々と設定をしなくてはいけない)
	* [describe-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-instance-requests.html)
	* [request-spot-instances](http://docs.aws.amazon.com/cli/latest/reference/ec2/request-spot-instances.html)
	* [cancel-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/cancel-spot-instance-requests.html)
* スポット群リクエスト(spot-fleet-requests)は新しい形式(設定が短くて、扱い易い)
	* [describe-spot-fleet-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-fleet-requests.html)
	* [request-spot-fleet](http://docs.aws.amazon.com/cli/latest/reference/ec2/request-spot-fleet.html)
	* [cancel-spot-fleet-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/cancel-spot-fleet-requests.html)

でawscliのコマンドが違うよ。

またコンソール画面も少しわかりづらいのでお気をつけてください。

![スポットリクエストコンソール画面](https://raw.githubusercontent.com/ryurock/qiita_images/master/aws_console_spot_fleet.gif)



## 今回やること

AMIはアマゾンが提供している東京リージョンの[amazon linux AMI](https://aws.amazon.com/jp/amazon-linux-ami/)でt1.microをaws-cliで1台立ち上げてみて、立ち上げたインスタンスを落としてみる。

基本は[【新機能】AWS CLIがアップデート！新機能「EC2 Spot Fleet API」が超便利！](http://dev.classmethod.jp/cloud/aws/introduce-to-ec2-spot-fleet-api/)の丸コピでほぼいけた。


## 流れ

### スポットリクエスト郡リクエストを実行できるIAMロールを作成する

ここらへんは[【新機能】AWS CLIがアップデート！新機能「EC2 Spot Fleet API」が超便利！](http://dev.classmethod.jp/cloud/aws/introduce-to-ec2-spot-fleet-api/)のIAMロールの作成でキャプチャ込で説明していますので割愛します。

IAMロールを作成したら、ロール ARNの情報が後で必要になるのでコピっといてください。


### 作成するAMIイメージ情報を取得する

下記のAMIはアマゾンが提供している東京リージョンの[amazon linux AMI](https://aws.amazon.com/jp/amazon-linux-ami/)

```
aws ec2 describe-images --image-ids ami-393c1957
```


t系シリーズ以外なら多分こっち

```
aws ec2 describe-images --image-ids ami-383c1956
```


### スポットインスタンスの入札価格を決める

こんな感じで調べてもいいし

```
aws ec2 describe-spot-price-history --instance-types t1.micro --availability-zone ap-northeast-1c --product-descriptions Linux/UNIX --start-time 2016-02-05T11:34:00Z --end-time 2016-02-05T11:34:00Z
```

[コンソール画面](http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-spot-instances-history.html)から確認してもいいです。



### スポットインスタンス郡リクエストを行う為の設定ファイルを作成する

json形式で詳細な設定は[request-spot-fleet](http://docs.aws.amazon.com/cli/latest/reference/ec2/request-spot-fleet.html)を読んでみてください。

以下今回の要件を満たすconfig.jsonは下記

```
{
    "TargetCapacity": 1,
    "SpotPrice": "0.0035",
    "IamFleetRole": "arn:aws:iam::1234567890:role/ARN情報",
    "LaunchSpecifications": [
        {
            "ImageId": "ami-393c1957",
            "KeyName": "your key name", #ある場合
            "SecurityGroups": [
              { "GroupId":"セキュリティグループId"} #セキュリティグループに入れたい場合
            ],
            "InstanceType": "t1.micro"
        }
    ]
}
```

* TargetCapacityはスポットインスタンスの台数
* SpotPriceは入札価格
* IamFleetRoleは先程作成したIAMロールの「ARNの情報」


を記載してください。


### スポット郡リクエストでスポットインスタンスを入札してみる

t1.microを一台立ち上げてみましょう

```
aws ec2 request-spot-fleet --spot-fleet-request-config file://config.json --region ap-northeast-1
```

### スポット郡リクエストの履歴をみてみる

スポット郡リクエストの履歴で最新の1件を取ってみる


```
aws ec2 describe-spot-fleet-requests --max-results 1
```

まだ--filterは実装されていないっぽい。


### スポット郡リクエストで作成したインスタンスの情報を取得してみる

先ほどのコマンドで取得した

SpotFleetRequestConfigs.SpotFleetRequestIdを ``` --spot-fleet-request-id ``` に記載する


```
aws ec2 describe-spot-fleet-instances --spot-fleet-request-id sfr-xxxxxx-xxxxx-xxx-xxxx-xxxxxxxxxx
```

コンソールでスポットインスタンスが立ち上がっていることを確認してみてください。


### スポット郡リクエストでスポットインスタンスを入札のキャンセルする

これをしないとスポットインスタンスを落としても落としてもゾンビのように蘇るのでご注意を

```
aws ec2 cancel-spot-fleet-requests --spot-fleet-request-ids sfr-xxxxxx-xxxxx-xxx-xxxx-xxxxxxxxxx --terminate-instances
```

これでスポット郡リクエスト自体のキャンセルとそれに関連するインスタンスが削除されます。


## 【補足】Query編

### スポット郡リクエストで状態がactiveなものの一覧を取得する

* [describe-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-instance-requests.html)

```
aws ec2 describe-spot-fleet-requests --query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active' ]"
```

結果

```
[
    {
        "SpotFleetRequestId": "sfr-xxxxxx-xxxx-46fc-9f74-13f464e11210",
        "SpotFleetRequestConfig": {
            "LaunchSpecifications": [
                {
                    "EbsOptimized": false,
                    "InstanceType": "t1.micro",
                    "ImageId": "ami-393c1957"
                }
            ],
            "IamFleetRole": "arn:aws:iam::123456789:role/your-role",
            "TargetCapacity": 2,
            "ExcessCapacityTerminationPolicy": "Default",
            "SpotPrice": "0.0035",
            "AllocationStrategy": "lowestPrice"
        },
        "CreateTime": "2016-02-07T03:34:36.485Z",
        "SpotFleetRequestState": "active"
    }
]
```

SpotFleetRequestIdだけ取得したい場合(shell用)

```
aws ec2 describe-spot-fleet-requests --query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" | jq -r ".[].SpotFleetRequestId"
```

### スポット郡リクエストの状態がactiveなものでスポット郡リクエストのスポットインスタンス情報をまとめて取得する

* [describe-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-instance-requests.html)

``` describe-spot-fleet-instances ``` のオプション ``` --spot-fleet-request-id ``` は複数指定できないので ``` xargs -n 1 ``` で１つずつ処理

```
aws ec2 describe-spot-fleet-requests --query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" | jq -r ".[].SpotFleetRequestId" |xargs -n 1 aws ec2 describe-spot-fleet-instances --spot-fleet-request-id
```

#### 上記でインスタンスIDだけ取得したい場合

* [describe-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-instance-requests.html)
* [describe-spot-fleet-instances](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-fleet-instances.html)

```
aws ec2 describe-spot-fleet-requests \
--query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" \
| jq -r ".[].SpotFleetRequestId" \
|xargs -n 1 aws ec2 describe-spot-fleet-instances \
--query "ActiveInstances[*].InstanceId" --output text --spot-fleet-request-id 
```

#### 上記で更にインスタンスの詳細な情報が欲しい場合

ワンライナーおじさん心が止まらない・・・

* [describe-spot-instance-requests](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-instance-requests.html)
* [describe-spot-fleet-instances](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-spot-fleet-instances.html)
* [describe-instances](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html)

を繋げる３連技
状態がスポットインスタンスのステータスがactiveなものだけにしている

```shell
aws ec2 describe-spot-fleet-requests \
--query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" \
| jq -r ".[].SpotFleetRequestId" \
|xargs -n 1 aws ec2 describe-spot-fleet-instances \
--spot-fleet-request-id \
--query "ActiveInstances[*].InstanceId" \
--output text \
|xargs aws ec2 describe-instances \
--filters "Name=instance-state-code,Values=16" \
--instance-ids
```


#### 上記で更にパブリックIPだけの情報が取得したい場合

```
aws ec2 describe-spot-fleet-requests \
--query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" \
| jq -r ".[].SpotFleetRequestId" \
|xargs -n 1 aws ec2 describe-spot-fleet-instances \
--spot-fleet-request-id \
--query "ActiveInstances[*].InstanceId" \
--output text \
|xargs aws ec2 describe-instances \
--filters "Name=instance-state-code,Values=16" \
--query "Reservations[*].Instances[].PublicIpAddress" \
--output text \
--instance-ids
```

### [ansible](http://www.ansible.com/)のinventory fileを一発で作るワンライナー

先頭のエコーはinventory fileのグループ名

```
echo "[hoge]"; aws ec2 describe-spot-fleet-requests \
--query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" \
| jq -r ".[].SpotFleetRequestId" \
|xargs -n 1 aws ec2 describe-spot-fleet-instances \
--spot-fleet-request-id \
--query "ActiveInstances[*].InstanceId" \
--output text \
|xargs aws ec2 describe-instances \
--filters "Name=instance-state-code,Values=16" \
--query "Reservations[*].Instances[].PublicIpAddress" \
--output text \
--instance-ids \
|xargs -n 1 echo > inventory_file
```

### スポット郡リクエストで状態がactiveなスポット郡リクエストをキャンセルするワンライナー

所定時間過ぎたら実行するとかね

```
aws ec2 describe-spot-fleet-requests --query "SpotFleetRequestConfigs[?SpotFleetRequestState == 'active']" | jq -r ".[].SpotFleetRequestId" |xargs aws ec2 cancel-spot-fleet-requests --terminate-instances --spot-fleet-request-ids
```



## 最後に

最初全然わけわからなくて頭が禿げ上がりそうになった・・・・