Closed15

FISを使ってスポットインスタンスの停止をテストする

not75743not75743

FISとは?

AWS Fault Injection Simulatorの略。
AWSサービスに対し疑似障害を起こし、その様子をレポートすることが出来るマネージドサービス。

https://docs.aws.amazon.com/fis/latest/userguide/what-is.html

対象サービスは?

以下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)

not75743not75743

例えばEC2だと何が出来る?

FISのテンプレートを見ると

  • EC2の再起動
  • スポットインスタンスの停止
  • EC2の停止
  • EC2の削除

がありました

not75743not75743

スポットインスタンスの停止を試してみる

terraformで関連リソースを用意し、いろいろ遊んで見る
EC2はスポットインスタンス・persistentにして、停止の様子を伺う

not75743not75743

コード

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-timeterminateされるようにした

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/spot_instance_request

not75743not75743

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ならタグ付けデフォルトでできるかな...そっちのほうがよかったっぽいな...

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag
https://discuss.hashicorp.com/t/aws-spot-instance-request-tags-wont-apply-to-instance/35750/2

not75743not75743

FISで使用するIAMロール

FISがEC2を操作するためのIAMロールを設定します。
AWSFaultInjectionSimulatorEC2AccessというEC2操作用のマネージドポリシーがあるので、遠慮なく使用します。
https://docs.aws.amazon.com/ja_jp/fis/latest/userguide/security-iam-awsmanpol.html

こんな感じです

{
    "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": "*"
        }
    ]
}
not75743not75743

こんな感じでアタッチ出来たので使ってみます。
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"
}
not75743not75743

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"
}
not75743not75743

FISを試すまでの流れ

  • 実験テンプレートを作成する
  • 実験テンプレートを元に実験を開始する
  • システムの稼働状況を確認する

テンプレート設定箇所

  • Actions
    • Targetに対してどのような実験を行うか選択する
    • 今回はスポットインスタンスの停止terminate_spot_instanceを選択する
  • Targets
    • 対象のサーバ、システムを選択する
    • 今回はNameタグでスポットインスタンスを指定します。
  • ServiceAccess
    • FISが実験を行うためのIAMロール
    • Terraformで作成したものを指定します。
  • Logs
    • 実験のログ
    • Terraformで作成したLogグループを指定します。
not75743not75743

テンプレートのexport

テンプレートはjson形式でエクスポートすることが出来ます。
それを元に実験テンプレートをawscliで作成することも可能です。

awscli

$ aws fis create-experiment-template --cli-input-json file://template.json

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>
not75743not75743

実験の開始

作成したテンプレートから「Start Experiment」を選択し、実験を開始します。
「Experiments」から各実験について知ることが出来ます

not75743not75743

スポットインスタンスの停止を確認

実験によって停止していることを確認します
OKですね

not75743not75743

ログを見る

今回は/fis/logs/に格納するようにしました
いつActionが実行されたか、などがわかります

このスクラップは2023/06/07にクローズされました