AWS Fault Injection Simulatorを使った障害試験を試してみる（その１：アクション概要とおためし実行）

# はじめに
AWS等のクラウド環境で障害試験を行う際、擬似的に障害を起こすのが難しく頭を悩ませていたところ、`AWS Fault Injection Simulator`（以下`AWS FIS`）という障害試験に役立つサービスがあることを知ったので、試してみようと思います。

- 【次】[AWS Fault Injection Simulatorを使った障害試験を試してみる（その２：色々なアクション実行）](https://qiita.com/sakai00kou/items/a15c396a1b9f241a62a9)

# AWS Fault Injection Simulator（AWS FIS）とは
AWS環境で特定の障害を擬似的に発生させることができるサービスです。

最近でいうとNetflix社が**カオスエンジニアリング**と呼ばれる、「**あえて本番環境で擬似的な障害をランダムに発生させて、システムの可用性向上や対応力を養う**」という手法を考案し、擬似的に障害を発生させる`Chaos Monkey`も公開されておりますが、`AWS FIS`もAWS環境上で`Chaos Monkey`と同じような疑似障害を発生させることができるサービスとなります。

`Chaos Monkey`は私は使ったことがないのでどのような動きをするか把握できておりませんが、`AWS FIS`はランダムに障害を発生させるような動作ではなく、あらかじめ作成したシナリオに従って疑似障害を発生させるサービスとなるため、どちらかと言うと以前から開発現場で行われている「**障害発生時に意図した切り替え動作や状態になるかを確認する**」障害試験として使うことが多いかと思います。

以下より`AWS FIS`で実際に行えるアクションをまとめます。

# 指定可能なアクション一覧
2023年6月現在、指定可能なアクションは以下42アクションとなります。

今回は１つ１つ細かな設定までは解説しませんが、各種アクションの詳細は以下AWSのドキュメントに書かれているので、それぞれのアクションで設定できる内容などはドキュメントを参照してください。

- [AWS FIS actions reference](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html)
- [Use Systems Manager SSM documents with AWS FIS](https://docs.aws.amazon.com/fis/latest/userguide/actions-ssm-agent.html)

|アクション種別|アクションタイプ|説明|
|:--|:--|:--|
|CloudWatch|aws:cloudwatch:assert-alarm-state|指定アラームのアラーム状態の指定|
|EBS|aws:ebs:pause-volume-io|ターゲットEBSボリュームのI/O操作の一時停止|
|EC2|aws:ec2:reboot-instances|指定したEC2インスタンスの再起動|
|EC2|aws:ec2:send-spot-instance-interruptions|指定したEC2スポットインスタンスの中断|
|EC2|aws:ec2:stop-instances|指定したEC2インスタンスの停止|
|EC2|aws:ec2:terminate-instances|指定したEC2インスタンスの終了|
|ECS|aws:ecs:drain-container-instances|ECSクラスタの基盤となるEC2インスタンスのドレイニング|
|ECS|aws:ecs:stop-task|ECSクラスタの指定したECSタスクの停止|
|ECS|aws:ecs:task-cpu-stress|AWSFIS-Run-CPU-Stressアクションを利用したCPUストレスの実施|
|ECS|aws:ecs:task-io-stress|AWSFIS-Run-IO-Stressアクションを利用したIOストレスの実施|
|ECS|aws:ecs:task-kill-process|AWSFIS-Run-Kill-Processアクションを利用した指定プロセスの停止|
|ECS|aws:ecs:task-network-blackhole-port|AWSFIS-Run-Network-Blackhole-Portアクションを利用したトラフィックの拒否|
|ECS|aws:ecs:task-network-latency|AWSFIS-Run-Network-Latency-Sourcesアクションを利用したネットワークレイテンシの追加|
|ECS|aws:ecs:task-network-packet-loss|AWSFIS-Run-Network-Packet-Loss-Sourcesアクションを利用したパケット損失の追加|
|EKS|aws:eks:inject-kubernetes-custom-resource|指定したKubernetesカスタムリソースをターゲットEKSクラスタに挿入|
|EKS|aws:eks:pod-cpu-stress|指定したPodにCPUストレスの実施|
|EKS|aws:eks:pod-delete|指定したPodの削除|
|EKS|aws:eks:pod-io-stress|指定したPodにIOストレスの実施|
|EKS|aws:eks:pod-memory-stress|指定したPodにメモリストレスの実施|
|EKS|aws:eks:pod-network-blackhole-port|指定したPodの送信トラフィックの拒否|
|EKS|aws:eks:pod-network-latency|指定したPodにネットワークレイテンシの追加|
|EKS|aws:eks:pod-network-packet-loss|指定したPodにパケット損失の追加|
|EKS|aws:eks:terminate-nodegroup-instances|EKSクラスタの基盤となるEC2インスタンスの終了|
|障害挿入|aws:fis:inject-api-internal-error|AWSサービスの特定のAPI操作に対するAPI内部エラーの挿入|
|障害挿入|aws:fis:inject-api-throttle-error|AWSサービスの特定のAPI操作に対するAPIスロットルエラーの挿入|
|障害挿入|aws:fis:inject-api-unavailable-error|AWSサービスの特定のAPI操作に対するAPI使用不可エラーの挿入|
|待機|aws:fis:wait|指定した期間待機|
|ネットワーク|aws:network:disrupt-connectivity|ターゲットサブネットへの指定トラフィックの拒否|
|RDS|aws:rds:failover-db-cluster|ターゲットDBクラスタでのフェイルオーバの実施|
|RDS|aws:rds:reboot-db-instances|ターゲットDBインスタンスの再起動|
|Systems Manager|aws:ssm:send-command|指定したSSMドキュメントの実行|
|Systems Manager|aws:ssm:start-automation-execution|指定したSystems Manager Automationの実行|
|SSM documents|AWSFIS-Run-CPU-Stress|stress-ngを使ったCPUストレスの実施|
|SSM documents|AWSFIS-Run-Disk-Fill|fallocateコマンドを使ったディスクフル障害の実施|
|SSM documents|AWSFIS-Run-IO-Stress|stress-ngを使ったIOストレスの実施|
|SSM documents|AWSFIS-Run-Kill-Process|killallコマンドを使った指定プロセスの停止|
|SSM documents|AWSFIS-Run-Memory-Stress|stress-ngを使ったメモリストレスの実施|
|SSM documents|AWSFIS-Run-Network-Blackhole-Port|iptablesを使ったトラフィックの拒否|
|SSM documents|AWSFIS-Run-Network-Latency|tcツールを使ったネットワークレイテンシの追加|
|SSM documents|AWSFIS-Run-Network-Latency-Sources|tcツールを使ったネットワーク遅延とジッターの追加|
|SSM documents|AWSFIS-Run-Network-Packet-Loss|tcツールを使ったパケット損失の追加|
|SSM documents|AWSFIS-Run-Network-Packet-Loss-Sources|tcツールを使った特定の送信元との間へのパケット損失の追加|

## 各アクションについて
一覧を見ただけでは分かりづらいアクションもあるので、以下でアクション種別ごとに簡単な概要をまとめます。

### CloudWatch
指定したアラームのアラーム状態を任意に変えることができます。

擬似的にアラーム状態を変えるだけなので実際のリソースには影響ありませんが、擬似的な障害を発生させづらいアラームが想定通りにメールやSlack通知されるかなど確認する際に便利です。

### EBS
説明に記載されている通り、EBSボリュームのI/O操作を一時的に停止するアクションとなります。

条件として、EC2インスタンスにアタッチされているEBSボリュームは**どちらも同じAZに存在する必要**があり、さらに**Nitroシステム上に構築されたEC2インスタンスにアタッチされている**必要があります。

そのため、使用しているEC2インスタンスタイプによってはこのアクションを使った試験ができないことに注意してください。

### EC2
EC2の再起動などを行うアクションとなります。

実際に指定のEC2インスタンスに対して指定したアクションが実行されてしまうので、**特に`aws:ec2:terminate-instances`はEC2インスタンスが本当に削除されてしまいます。**

まさに破壊的なアクションとなるので使用する際は注意しましょう。

### ECS
ECSを動かしているEC２インスタンス自体に対してドレイニングを行うアクションとECSタスクを停止させるアクション、また、後述の`SSM Documents`を利用した各種ストレスアクションとなります。

`aws:ecs:drain-container-instances`はECSのコンテナを動作させているコンテナインスタンスとなるEC2インスタンス側へのアクションとなるため、AWS側でコンテナインスタンスを管理している`Fargate`型のECSでは使用できません。

### EKS
EKSは詳しくないので詳細はAWSのドキュメントを参照願います。

### 障害挿入
特定のAPIアクセスに対してそれぞれのAPIエラーを挿入することができます。

### 待機
指定時間待つだけのアクションです。

`AWS FIS`では１つの試験用テンプレートの中で複数のアクションを実行することができるので、次のアクションに行くまでにしばらく待機させたい場合に指定します。

### ネットワーク
指定したサブネットへのトラフィックを拒否することができます。

### RDS
RDSのフェイルオーバやDBインスタンスの再起動を行うことができます。

### Systems Manager
`Systems Manager`の`Run Command`と`Automation`機能を使用するアクションとなります。

独自に障害試験用の`Systems Manager`ドキュメントを作成してあるような場合に使います。

### SSM documents
あらかじめ`Systems Manager`のドキュメントとして登録されているストレス・障害試験系のドキュメントを実行するものとなります。

`AWS FIS`の画面上でAWS作成のドキュメントの値を指定できたりする以外は、アクション種別`Systems Manager`の`aws:ssm:send-command`とやっていることは同じです。

もちろん`Systems Manager`のドキュメントに登録されているので、`AWS FIS`を使わなくても`Systems Manager Run Command`で実行することも可能です。

注意点としては、「[指定可能なアクション一覧](#指定可能なアクション一覧)」の説明欄に記載しているコマンドで障害を発生させるため、**障害試験実行前にターゲットに対してツールのインストールが行われます。**

インストールパッケージなど細かく管理しているシステムの場合は試験用のインスタンスを準備したり、試験終了後、バックアップからリストアするなど行ってください。

# 実験テンプレートの作成
実際にAWSマネジメントコンソール画面上から、疑似障害の設定を行っていこうと思います。

`AWS FIS`ではどのような疑似障害を発生させるかを設定したまとまりを「**実験テンプレート**」と言い、作成した実験テンプレートを実行することで、テンプレートに設定されている疑似障害を指定したターゲットに対して発生させることができるようになっております。

まずは疑似障害のアクションを設定した「**実験テンプレート**」を以下の流れで作成していきます。

- [実験テンプレート名の指定](#実験テンプレート名の指定)
- [疑似障害アクションの指定](#疑似障害アクションの指定)
- [ターゲットの指定](#ターゲットの指定)
- [サービスアクセス](#サービスアクセス)
- [停止条件](#停止条件)
- [ログ](#ログ)
- [タグ](#タグ)

## 実験テンプレート名の指定
実験テンプレートの設定を行うため、「**AWS FIS**」→「**実験テンプレート**」より「**実験テンプレートを作成**」を選択します。

![Monosnap_20230212_103236.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/b198b1f1-34a9-573b-a63b-cd865e1207c5.png)

設定画面では「**説明と名前**」欄で以下の設定を行います。

「**名前**」は指定しなくても良いですが、指定すると設定の最後にある「**タグ**」にキーが「**Name**」、値が「**名前**」で指定した名前が自動的に定義されます。

|項目|設定|備考|
|:--|:--|:--|
|説明|実験テンプレートの名前を指定|任意の名前を指定|
|名前（オプション）|任意|ここで指定した名前がタグ名となる|

## 疑似障害アクションの指定
「**アクション**」欄の「**アクションを追加**」を選択することで以下のようなアクション設定項目が表示されます。

「**アクションタイプ**」を選択すると、「[指定可能なアクション一覧](#指定可能なアクション一覧)」でまとめたアクション一覧が表示され、選択することでアクションごとに異なる設定が行えるようになっております。

また、「**次のあと開始（オプション）**」は、現在設定しているアクションの後に実行したいアクションがある場合に指定することで、例えばEC2インスタンスを停止させた後に別のEC2インスタンスに対して再起動させると言った一連のアクションを同一実験テンプレート内で指定できます。

![Monosnap_20230212_105648.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/80d25a92-63e1-cf75-384d-bf047eefd803.png)

以下は「**アクションタイプ**」に「**aws:ec2:stop-instances**」を選択した場合の項目例。

初回は「**ターゲット**」欄に何も表示されていない状態か自動で名前が入っているかもしれませんが、次項でターゲット指定するため、そのままで構いません。

また、「**Start Instances After Duration**」はオプションとなっているため、指定しなくても問題ありませんが、指定すると、指定時間待機してからアクションを実行する動作となります。

![Monosnap_20230212_110117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/53e3c77b-1ef3-c396-0e20-060556196724.png)

## ターゲットの指定
EC2インスタンスのターゲットの指定には「**リソースID**」、または「**リソースタグ、フィルター、パラメータ**」で指定することができ、「**選択モード**」により指定したターゲット全てを対象とするか、特定の数やパーセンテージ指定で対象を決めるかなど指定できます。

また、今回の場合は「**リソースタグ、フィルター、パラメータ**」を選択すると、どのリソースタグが付与されている対象をターゲットとするかが指定できる「**リソースタグ**」と、オプションで指定した属性でリソースフィルタができる「**リソースフィルター**」の設定を行うことができます。

「**リソースフィルター**」は例えばターゲットで指定した対象のうち、`ap-northeast-1a`に存在するターゲットのみを対象とするといったフィルタリングを行うことが可能なので、「**リソースタグ**」だけでは絞りきれないときでも柔軟に指定できます。

実際に設定を行っていきますが、ただ単純に停止するEC2インスタンスを指定しても面白くないので、今回は以下のように「**リソースタグ、フィルター、パラメータ**」でキーが「**Type**」、値が「**web**」のタグが付与されているEC2インスタンスを対象として、そのうちの50%のターゲットのみ停止する設定としてみようと思います。

![Monosnap_20230212_120129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/e7f7c26e-a1a4-64c4-9c3e-88b550a1c322.png)

## サービスアクセス
`AWS FIS`に付与するIAMロールの指定を行います。

既存のIAMロールを選択することもできますが、新しいIAMロールを作成することで、アクションで指定した操作に対してアクセス許可されたIAMロールが新たに作成されます。

![Monosnap_20230212_122221.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/e269d4e9-e66a-8f32-0ec5-076c74d2396c.png)

## 停止条件
特定の`CloudWatch`アラームがトリガーされた際に`AWS FIS`の実行を停止する条件を指定できます。

例えば、`AWS FIS`を実行した際に、想定外にCPUやメモリリソースが上昇した場合に自動停止させるようなことが可能です。

以下のスクリーンショットにも記載されている通り、`CloudWatch`アラームをトリガーとしているため、当然トリガーさせたい`CloudWatch`アラームを先に作成しておく必要があります。

![Monosnap_20230212_122243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/51f923f8-c57c-0775-da24-219289bf6a0e.png)

## ログ
指定することで`Amazon S3`と`CloudWatch Logs`にログ出力することができます。

デフォルトではどちらもチェックされていないためログ出力されないようになっておりますが、チェックをすることで、以下のような設定を行うことができます。

![Monosnap_20230212_122302.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/011516ce-1754-cc06-5ba1-b64aae49e81f.png)

## タグ
「**説明と名前**」の「**名前**」で名前を指定している場合は、以下のように`Name`のタグが付与されます。

その他にタグを付与させたい場合はタグを追加してください。

![Monosnap_20230212_122319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/f4f8dd52-cc26-f8e5-cd41-54a851901f51.png)

# 実験テンプレートの実行
上記設定後、「**実験テンプレートを作成**」とすることでテンプレートが作成されるため、作成されたテンプレートにチェックを行い、「**実験を開始**」とすることでアクションを実行できます。

![Monosnap_20230212_141226.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/94bb34fd-e5d9-f18a-f463-8ac05969eb34.png)

今回は先程説明したとおり、「**Type**」が「**web**」のEC2インスタンスを50%停止させるようにアクションを設定したので、以下スクリーンショットのうち、`testinstance1`か`testinstance2`のどちらかが停止することを確認してみようと思います。

![Monosnap_20230212_141934.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/f35934e0-954d-407f-e56f-8aea0d953fff.png)

「**実験を開始**」を選択すると、破壊的なアクションを実行する旨の再確認表示が出るため、ここで「**開始**」と入力して「**実験を開始**」を選択します。

![Monosnap_20230212_142322.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/567011c3-093e-7c81-ee90-3f68315c0d27.png)

成功すると「**アクション**」タブに`Completed`と表示され、アクション終了となります。

![Monosnap_20230212_143116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/b9a6a497-715c-b6c1-a14a-3ff7787f856c.png)

アクション実行後のEC2インスタンスの状態としては以下となり、想定通り「**Type**」が「**web**」のタグが付与されているEC2インスタンスの半分が停止されていることが確認できました。

![Monosnap_20230212_143810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/b5e4e34a-d3de-057a-0830-c5ff81fa4afd.png)

ちなみに実行したアクションのその他のタブでは以下のような内容が確認できます。

「**ターゲット**」タブではターゲット設定内容が確認できます。

![Monosnap_20230212_143201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/2a8e7cf3-0c63-e85a-ff33-77fba4a372a2.png)

「**タグ**」はアクションに付与したタグが確認できるだけなので省略。

「**タイムライン**」ではアクションを実行した時間が確認できます。

今回は１アクションのみだったので、１つだけですが、複数アクションを指定していればそれぞれのアクションでどの程度時間がかかったかが確認できます。

![Monosnap_20230212_143217.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/5198f15b-9a1d-2818-b7d8-9e22430ea427.png)

「**ログイベント**」は今回実行したアクションのログが確認できます。

`S3`や`CloudWatch Logs`にも転送していれば同様のログがそちらからも確認できます。

![Monosnap_20230212_143236.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/2a0c7af6-6bc5-9bf6-8d8c-7d6e5875471c.png)

# おわりに
今回は`AWS FIS`でどのようなアクションが指定できるかのまとめと、お試しでEC2インスタンス停止を行うアクションを設定して動かしてみました。

今回のような単純な試験以外にも、擬似的に発生させるには手間がかかるAPI実行エラーや数%だけエラーとするといった障害、また、`Systems Manager`の`Run Command`と連携しているので、SSMドキュメントを準備しておけばかなり柔軟に障害試験を行うことができるのは試験の幅が広がると感じました。

次回はその他のアクションもいくつか試してみてどのような動きをするか確認してみたいと思います。