FISを使ってスポットインスタンスの停止をテストする
FISとは?
AWS Fault Injection Simulator
の略。
AWSサービスに対し疑似障害を起こし、その様子をレポートすることが出来るマネージドサービス。
対象サービスは?
以下4つでした
Amazon Elastic Compute Cloud (Amazon EC2)
Amazon Elastic Container Service (Amazon ECS)
Amazon Elastic Kubernetes Service (Amazon EKS)
Amazon Relational Database Service (Amazon RDS)
例えばEC2だと何が出来る?
FISのテンプレートを見ると
- EC2の再起動
- スポットインスタンスの停止
- EC2の停止
- EC2の削除
がありました
スポットインスタンスの停止を試してみる
terraformで関連リソースを用意し、いろいろ遊んで見る
EC2はスポットインスタンス・persistentにして、停止の様子を伺う
コード
githubへのアップロードはあとで取り急ぎスポットインスタンス部分
## SpotInstance
resource "aws_spot_instance_request" "test" {
ami = "ami-0c16ff0f860575572"
associate_public_ip_address = true
instance_type = "t3.small"
iam_instance_profile = aws_iam_instance_profile.SSM-instance-profile.name
vpc_security_group_ids = [aws_security_group.sg.id]
subnet_id = var.public1ID
spot_type = "one-time"
instance_interruption_behavior = "terminate"
root_block_device {
volume_size = 20
volume_type = "gp3"
}
tags = {
Name = "test-spot"
}
}
resource "aws_ec2_tag" "tag" {
resource_id = aws_spot_instance_request.test.spot_instance_id
key = "Name"
value = "SpotTest"
}
aws_instance
とパラメータは同じで、Spot特有のオプションspot_type
などを追記していく。
今回はFISを試した後にterminateされてほしいので、one-time
でterminateされるようにした
aws_ec2_tag
でスポットインスタンスへタグ付け
aws_spot_instance_request
で作成したスポットインスタンスにタグは付与されません。
スポットインスタンスリクエストにはタグ(default_tags含め)が付与されます。
スポットインスタンス本体にタグを割り当てるためにaws_ec2_tag
を使用します。
resource "aws_ec2_tag" "tag" {
resource_id = aws_spot_instance_request.test.spot_instance_id
key = "Name"
value = "SpotTest"
}
※スポットインスタンスが生成されてからでないとタグ付けは成功しないため、実行に失敗した場合は再度terraform applyをすればよいです。
※LaunchTemplateならタグ付けデフォルトでできるかな...そっちのほうがよかったっぽいな...
FISで使用するIAMロール
FISがEC2を操作するためのIAMロールを設定します。
AWSFaultInjectionSimulatorEC2Access
というEC2操作用のマネージドポリシーがあるので、遠慮なく使用します。
こんな感じです
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:RebootInstances",
"ec2:SendSpotInstanceInterruptions",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:TerminateInstances"
],
"Resource": "arn:aws:ec2:*:*:instance/*"
},
{
"Effect": "Allow",
"Action": [
"kms:CreateGrant"
],
"Resource": [
"arn:aws:kms:*:*:key/*"
],
"Condition": {
"StringLike": {
"kms:ViaService": "ec2.*.amazonaws.com"
},
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
},
{
"Effect": "Allow",
"Action": [
"ssm:SendCommand"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ssm:*:*:document/*"
]
},
{
"Effect": "Allow",
"Action": [
"ssm:CancelCommand",
"ssm:ListCommands"
],
"Resource": "*"
}
]
}
こんな感じでアタッチ出来たので使ってみます。
aws_iam_policy_attachment
ではアタッチ出来なかったのですがaws_iam_role_policy_attachment
とすることでroleに割当出来ました
## FIS IAMRole
resource "aws_iam_role" "FISRole" {
name = "FISRole"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "fis.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "FIS-policy-attachment" {
role = aws_iam_role.FISRole.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSFaultInjectionSimulatorEC2Access"
}
cloudwatch logs分のポリシー追加
AWSFaultInjectionSimulatorEC2Access
だけではcloudwatch logsにログ転送ができないため、適宜必要なポリシーをつけます。今回はCloudWatchLogsFullAccess
で妥協しました
resource "aws_iam_role_policy_attachment" "FIS-Logs-policy-attachment" {
role = aws_iam_role.FISRole.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
}
FISを試すまでの流れ
- 実験テンプレートを作成する
- 実験テンプレートを元に実験を開始する
- システムの稼働状況を確認する
テンプレート設定箇所
- Actions
- Targetに対してどのような実験を行うか選択する
- 今回はスポットインスタンスの停止
terminate_spot_instance
を選択する
- Targets
- 対象のサーバ、システムを選択する
- 今回はNameタグでスポットインスタンスを指定します。
- ServiceAccess
- FISが実験を行うためのIAMロール
- Terraformで作成したものを指定します。
- Logs
- 実験のログ
- Terraformで作成したLogグループを指定します。
テンプレートのexport
テンプレートはjson形式でエクスポートすることが出来ます。
それを元に実験テンプレートをawscliで作成することも可能です。
awscli
$ aws fis create-experiment-template --cli-input-json file://template.json
template.json
{
"description": "test template",
"targets": {
"SpotInstances-Target-1": {
"resourceType": "aws:ec2:spot-instance",
"resourceTags": {
"Name": "SpotTest"
},
"selectionMode": "ALL"
}
},
"actions": {
"terminate_spot_instance": {
"actionId": "aws:ec2:send-spot-instance-interruptions",
"parameters": {
"durationBeforeInterruption": "PT2M"
},
"targets": {
"SpotInstances": "SpotInstances-Target-1"
}
}
},
"stopConditions": [
{
"source": "none"
}
],
"roleArn": "arn:aws:iam::xxxxxxxxxxxx:role/FISRole",
"logConfiguration": {
"cloudWatchLogsConfiguration": {
"logGroupArn": "arn:aws:logs:ap-northeast-1:xxxxxxxxxxx:log-group:/fis/logs/:*"
},
"logSchemaVersion": 2
},
"tags": {
"Name": "terminate_spot_instance"
}
}
片付け方法
# テンプレートIDを出す
$ aws fis list-experiment-templates | jq -r '.experimentTemplates[].id'
# テンプレートIDを指定し、削除する
$ aws fis delete-experiment-template --id <ID>
実験の開始
作成したテンプレートから「Start Experiment」を選択し、実験を開始します。
「Experiments」から各実験について知ることが出来ます
スポットインスタンスの停止を確認
実験によって停止していることを確認します
OKですね
ログを見る
今回は/fis/logs/
に格納するようにしました
いつActionが実行されたか、などがわかります