【AWS】VSCode Remote-SSH＋EC2な開発環境を安く安全に作る〜3. スポットリクエスト作成〜

[前回](https://qiita.com/soujiroy/items/7798448fdc71a07005c6)で作成した起動テンプレートを使い実際にスポットリクエストを作成していきたいと思います。今回実施するのは以下の内容です。

1. スポットリクエストの作成
1. (オプション)スポットリクエスト起動用のLambda作成


# スポットリクエストの作成
[この画面](https://ap-northeast-1.console.aws.amazon.com/ec2/home?region=ap-northeast-1#SpotInstancesLaunch:)からスポットリクエストの作成を行います。以下の値以外はデフォルト値で大丈夫です。

* 起動パラメータ
  * 起動テンプレートを選択し、前回作成した起動テンプレートを選択
  * ネットワーク
    * 前提条件で作成済みのVPCを選択
    * アベイラビリティーゾーンは前回データ保存用EBSなどを作成したアベイラビリティーゾーンを選択
  * インスタンスタイプの要件
    * 選択したAMIや開発環境の要件に合わせて選択。 

最後に作成をクリックでスポットリクエストが作成され、スポットインスタンスが起動するようになります。また、オプション手順用にスポットリクエストの設定をJSON設定から保存しておきます。

![スクリーンショット 2022-12-03 11.45.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105456/cd794046-ec80-4871-5e31-fc2ef260b9a8.png)

# (オプション)スポットリクエスト起動用のLambda作成
上記でもスポットインスタンスを起動することはできるのですが毎回画面からスポットリクエストの条件を入力していくのは面倒なので事前に決めておいたスポットリクエストの定義に従ってスポットリクエストを作成してくれるLambda関数を作っておきたいと思います。


## LambdaにアタッチするIAMロールを作成
LambdaにアタッチするIAMロールを作成します。

許可ポリシー
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

ポリシーはAWSLambdaBasicExecutionRoleと以下の内容のポリシーをアタッチ。
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:RequestSpotFleet",
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::XXXXXXXXXX:role/*"
        }
    ]
}
```

## Lambda関数の作成
[ここ](https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/create/function)からLambda関数を作成します。ランタイムはPython、実行ロールに先ほど作成したIAMロールを選択しそれ以外はデフォルトで作成します。タイムアウト時間はデフォルトの3秒だとたまにタイムアウトしてしまうので10秒以上に設定します。

## Lambda関数の編集
作成したLambda関数のソースコードを以下の用に編集してデプロイします。
```python
import json
import boto3

def lambda_handler(event, context):
    client = boto3.client('ec2')
    client.request_spot_fleet(
        SpotFleetRequestConfig={
            #以下にスポットリクエスト作成時に保存したJSONの値を貼り付け
            "IamFleetRole": "arn:aws:iam::xxxxxxxxxxx:role/aws-ec2-spot-fleet-tagging-role",
            "AllocationStrategy": "priceCapacityOptimized",
            "TargetCapacity": 1,
            #ValidFromとValidUntilは消しておく
            "TerminateInstancesWithExpiration": True, #JSONから貼り付けたままだと'true'となっていてPythonのbooleanと判定されないので'True'に書き換え
            "Type": "request",
            "OnDemandAllocationStrategy": "lowestPrice",
            "LaunchSpecifications": [],
            "LaunchTemplateConfigs": [
                {
                    "LaunchTemplateSpecification": {
                        "LaunchTemplateId": "lt-XXXXXXXX",
                        "Version": "1"
                    },
                    "Overrides": [
                        {
                            "InstanceType": "t3.large",
                            "WeightedCapacity": 1,
                            "SubnetId": "subnet-XXXXXX"
                        }
                    ]
                }
            ]
        })
    return {
        'statusCode': 200,
        'body': json.dumps('success')
    }
```
## Lambda関数の実行
上記Lambda関数を実行することでスポットリクエストが作られ、スポットインスタンスが生成されます。任意のイベントをトリガーとして実行できますが、私はLambdaのテスト画面から実行しています。

以上でスポットリクエストの作成まで完了しました。[次回](https://qiita.com/soujiroy/items/f602a4171f056b1cb79c)はVSCodeの設定を行なっていきます。