カオスエンジニアリングツール「AWS Fault Injection Simulator(AWS FIS)」とは

OpenStandiaアドベントカレンダー21日目は、カオスエンジニアリングツールであるAWS Fault Injection Simulatorの紹介です。

# カオスエンジニアリングとは

あえて障害をおこし、その際にシステムが復旧できるかどうかを検証していくことです。

過去のOpenStandiaアドベントカレンダーでカオスエンジニアリングに関する記事があるので、興味ある方はぜひこちらもお読みください！
- https://qiita.com/naokiiiii/items/de20997a70922c01f754
- https://qiita.com/naokiiiii/items/e14a7cdad8f48ffe7542

# AWS Fault Injection Simulator(AWS FIS)とは

AWSが2021年から提供しているカオスエンジニアリングツールです。このツールを用いると、様々なAWSサービスに対して疑似的な障害を発生させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/bbf1f879-5303-c432-7cf6-a8c7b4e1467a.png)
[※ AWSサイトより引用](https://aws.amazon.com/jp/fis/)

AWS FISの利用の流れは上図の通りです。AWS FISでは、障害を発生させることを「実験」と呼びます。

1. Create an experiment template
    - どのような実験を行うかを「実験テンプレート」に記載します。
    - 実験テンプレートは複数作成可能です。
2. Start the experiment
    - 実験テンプレートを選択し、実験を開始します。
    - このとき、Amazon CloudWatch等のモニタリングツールで監視を行います。
3. Stop the experiment
    - 実験終了後も、システムの稼働状況を確認します。
4. View results
    - 実験中・実験後のシステム稼働状況をもとに、システム構成の改善を検討していきます。

## AWS FISを操作する方法について

AWS FISは他のAWSサービスと同様に、下記の通り様々な方法で操作できます。
- AWSマネジメントコンソール
    - https://aws.amazon.com/jp/blogs/news/aws-fault-injection-simulator-use-controlled-experiments-to-boost-resilience/
    - 上記リンクの通り、Webブラウザで簡単に操作できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/0f600194-4710-174c-c6b7-4a71d9588d00.png)

- AWS CLI
    - https://awscli.amazonaws.com/v2/documentation/api/latest/reference/fis/index.html?highlight=fis
    - 上記リンクのドキュメントに従って、コマンドラインで操作できます。下記例では、myfile.jsonに記載した設定を読み込んで実験テンプレートを作成しています。
        ```
        aws fis create-experiment-template --cli-input-json file://myfile.json
        ```
        ```:myfile.json
        {
            "description": "test-template",
            "targets": {
                "test-target": {
                    "resourceType": "aws:ec2:instance",
                    "resourceArns": [
                        "arn:aws:ec2:ap-northeast-1:[アカウントID]:instance/[インスタンスID]"
                    ],
                    "selectionMode": "ALL"
                }
            },
            "actions": {
                "test-action": {
                    "actionId": "aws:ec2:stop-instances",
                    "parameters": {},
                    "targets": {
                        "Instances": "test-target"
                    }
                }
            },
            "stopConditions": [
                {
                    "source": "none"
                }
            ],
            "roleArn": "arn:aws:iam::[アカウントID]:role/[IAMロール名]",
            "tags": {}
        }
        ```
- AWS SDK(リンク先はPython)
    - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/fis.html?highlight=fault%20injection
    - 下記例はPythonですが、JavaScriptやRubyといった他の言語も実装可能です。
    - 
        ```
        response = client.create_experiment_template(
            description='test-template',
            stopConditions=[
                {
                    'source': 'none'
                },
            ],
            targets={
                'test-target': {
                    'resourceType': 'aws:ec2:instance',
                    'resourceArns': [
                        'arn:aws:ec2:ap-northeast-1:[アカウントID]:instance/[インスタンスID]',
                    ],
                    'selectionMode': 'ALL'
                }
            },
            actions={
                'test-action': {
                    'actionId': 'aws:ec2:stop-instances',
                    'parameters': {},
                    'targets': {
                        'Instances': 'test-target'
                    }
                }
            },
            roleArn='arn:aws:iam::[アカウントID]:role/[IAMロール名]',
            tags={}
        )
        ```
    - AWS SDK対応しているため、AWS FISは[AWS Step Functions上での利用も可能](https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/supported-services-awssdk.html)です。[それを試すためのサンプルコードもAWS公式から提供されています。](https://github.com/aws-samples/aws-stepfunctions-examples/tree/main/sam/demo-fis-stepfunctions)

- AWS Fault Injection Simulator API
    - https://docs.aws.amazon.com/fis/latest/APIReference/Welcome.html
    - POSTやGETを用いて操作できます。

IaCコンテンツも充実してきています。AWS FIS自体の機能が成熟してきたら、これらと組み合わせて利用する事例も出てきそうですね。

- AWS CDK
    - https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_fis-readme.html
- Terraform
    - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/fis_experiment_template
- Pulumi
    - https://www.pulumi.com/registry/packages/aws/api-docs/fis/

ちなみに、AWS FISをローカル上で試せるサードパーティー製フェイクツールも存在します。

- LocalStack Pro
    - https://docs.localstack.cloud/user-guide/aws/fis/

## 実験テンプレートで設定できる内容について

実験テンプレートでは、TargetsとActionsとStop conditionsを指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/a0ec037a-c1d3-6cbc-1064-10d010e0ac51.png)
[※ AWS公式ドキュメントより引用](https://docs.aws.amazon.com/ja_jp/fis/latest/userguide/what-is.html)

- Targets(ターゲット)：必須入力
    - どのAWSリソースで障害を起こすかを指定します。2022/12時点では、EC2やRDS、ECS、EKS、SSMが対象です。
    - AWSリソースを柔軟な方法で指定できます。例えば、EC2インスタンスを指定する際、下記のような選択をすることができます。
        - 特定のEC2インスタンスを手動で選択
        - 特定のタグがついたEC2インスタンスを選択
        - running状態のEC2インスタンス全て
- Actions(アクション)：必須入力
    - Targetsで指定したリソースにて、どのような障害を発生させるかを指定します。
    - 例えば下記アクションが存在します。他にも様々なアクションが存在し、それらは[AWS FISの公式ガイド](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html)に記載されています。
        - EC2インスタンスを停止
        - RDSを再起動
        - EKSの特定のノードグループのインスタンスを終了
        - 指定したスコープのネットワークを遮断（2022/10に追加された機能）
- Stop conditions(停止条件)：オプション
    - 設定したAmazon CloudWatchアラームをトリガーとして、実験を安全に停止できます。停止条件を複数設定することも可能です。
    - 設定しない場合は、アクションで設定した継続時間が経過した後に実験を停止します。

個人的には、「スポットインスタンスを中断する」や「ある特定のVPCのネットワークを遮断する」といったユースケースを実験できる点が特に有用だと感じています。
今後、より多くのアクションに対応していくこと（特に、ネットワークまわり）を楽しみにしております。

## 実験を行う際のTips
実際に下記構成でAWS FISを動かしたときに気になった点をTipsとして記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534839/6fcf0040-9dd0-845e-635d-0945a7dd4e86.png)


① AWS FISで実験を行うためには、AWS FIS自体に実験対象のAWSリソースを操作できる権限が必要です。
そのため、専用のIAMロールを作成し、実験テンプレートにアタッチする必要があります。

② 実験テンプレートは手動で削除できますが、実験結果は手動で削除できません。

③ オプション機能として、AWS FISの実験自体のログをAmazon S3かAmazon CloudWatch Logsに送信することができます。なお、取得できるログの例は[こちら](https://docs.aws.amazon.com/ja_jp/fis/latest/userguide/monitoring-logging.html#experiment-start)です。
ログがあるとどのような実験を行ったかをすぐ確認できるため、個人的にはログの取得を推奨します。

④ 実験中にAWSリソースをモニタリングするためには、Amazon CloudWatchが必須となります。

ダッシュボードでテスト中の挙動を確認する際、EC2インスタンスのデフォルト設定（基本モニタリング）では、メトリクスの取得間隔は5分です。

AWS FISのアクションの継続時間が5分未満の場合、デフォルトのままではメトリクス取得間隔が広すぎて正しいモニタリングができません。
以下のいずれかの対応を推奨します。
- AWS FISのアクションの継続時間を10分以上に設定
- [インスタンスの詳細モニタリングを有効化](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-cloudwatch-new.html)し、1分間隔でデータを取得
- [カスタムメトリクス](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/publishingMetrics.html)を用いて、メトリクスの取得間隔を短く設定（最小の取得間隔は1秒であり、取得間隔に応じて[メトリクスの保存期間も短くなる](https://aws.amazon.com/jp/cloudwatch/faqs/#AWS_resource_.26_custom_metrics_monitoring)）

⑤ CPU使用率やネットワーク送信量をモニタリングする際、実験対象によっては「もともとのCPU利用率が低い」、「検証環境であるため、ユーザからのネットワークアクセスがない」等の理由でAmazon CloudWatchによる観測が難しいケースがあります。
その場合は、事前にCPU使用率やネットワーク送信量がある程度の値となるように仕込みを行うことで、実験結果を確認しやすくなります。

参考までに、私は下記スクリプトを作成しました。
- sleepコマンドを繰り返し実行するスクリプト（実験対象のアプリケーションがデプロイされているインスタンス内に配置）
- 実験対象のアプリケーションへ繰り返しcurlを投げるスクリプト（実験するAWS構成外に用意）

⑥ AWS FISを利用する際に発生するコストの計算にご注意ください。

AWS FIS自体は、[実験を行うたびにアクションの実施時間だけコストがかかります。東京リージョンでは、1分あたり0.10ドル課金されます。](https://aws.amazon.com/jp/fis/pricing/)
AWS FISのアクティビティログを取得している場合は、Amazon S3やAmazon CloudWatch Logsのコストが発生します。
（※AWS FISからのログ送信自体には課金は生じません。）

また、「Amazon CloudWatchの詳細モニタリング有効化」や「カスタムメトリクスの作成」を行うと、そこにもコストが発生します。