AWS Fault Injection Service (FIS) | FIS を使ってみた
エンジニアの横田です。 クラウドインフラの信頼性を確保することは、多くの企業にとって重要な課題です。AWS Fault Injection Simulator(FIS)は、こうした信頼性の向上を支援する強力なツールです。
今回はこの AWS Fault Injection Simulator(FIS)を使ってみました。せっかくなので、 CloudFormation テンプレート化したので本ブログで紹介します。
決して CloudFormation での AWS Fault Injection Simulator(FIS)作成を試したかっただけではありません。断じて違います。
CloudFormation って何?という方は以前に ブログ記事 でご紹介していますので、そちらも是非ご確認ください。
※ 本ブログ記事の内容は 2024/10/30 時点の情報です。
目次
AWS Fault Injection Simulator(FIS)とは?
AWS Fault Injection Simulator(FIS)は、カオスエンジニアリングの概念をクラウド環境に導入するためのマネージドサービスです。AWS Fault Injection Simulator(FIS) を使うことで、システムの弱点を発見し、実際の障害に強いアーキテクチャを構築することができます。
具体的には、仮想的に障害を引き起こし、システムの耐障害性やリカバリー能力をテストします。
例えば、特定の EC2 インスタンスの停止やネットワーク遅延のシミュレーションを行い、その結果を分析することで、システムがどのように反応するかを確認できます。
このプロセスを通じて、未然に問題を発見し、迅速に対策を取ることが可能です。
AWS Fault Injection Simulator(FIS)のメリットとユースケース
AWS Fault Injection Simulator(FIS) の最大のメリットは、リアルな障害シナリオを安全にテストできることです。開発チームや運用チームは、障害が発生したときのシステムの動作を事前に確認することで、問題解決のスピードと精度を向上させることができます。
いくつかのユースケースを挙げると、以下のようなものがあります:
- システム全体の回復力テスト:特定のサービスがダウンしたときに、他のサービスがどのように対応するかを検証します。
- スケーラビリティの確認:トラフィックが急増したときの負荷テストを実施し、インフラのスケール対応力を評価します。
- 障害対応プロセスの訓練:オペレーションチームが障害発生時の手順をスムーズに実行できるかを訓練する機会を提供します。
例えば、ALB(Application Load Balancer)と EC2 インスタンスのオートスケーリング構成で、AWS Fault Injection Simulator(FIS) を利用して負荷を意図的に上げることで、インスタンスが自動的にスケーリングされるかを確認することができます。これにより、スケーリングポリシーが適切に設定されているかどうかをテストすることが可能です。
AWS Fault Injection Simulator(FIS)を CloudFormation で実装する手順
本ブログでは、CloudFormation テンプレートを使って、 ALB と EC2(オートスケーリング)構成で AWS Fault Injection Simulator(FIS)を使って負荷テストを実施する具体的な手順をご紹介します。
今回も rain でデプロイします。
rain について知らないよ〜って方は こちら で紹介しておりますのでぜひご確認ください。
1. CloudFormation テンプレートのデプロイ
下記のコードブロックの内容をお好みの ファイル名.yaml で保存してください。
本ブログでは blog-fis.yaml として使用します。
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Project:
Type: String
Default: blog-fis
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
InstanceType:
Type: String
Default: t3.micro
DesiredCapacity:
Type: Number
Default: 2
MaxCapacity:
Type: Number
Default: 3
Mappings:
Map:
CIDR:
VPC: 10.0.0.0/16
SubnetA: 10.0.0.0/24
SubnetC: 10.0.1.0/24
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !FindInMap [Map, CIDR, VPC]
EnableDnsSupport: true
EnableDnsHostnames: true
InternetGateway:
Type: AWS::EC2::InternetGateway
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: !FindInMap [Map, CIDR, SubnetA]
MapPublicIpOnLaunch: true
PublicSubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [1, !GetAZs '']
CidrBlock: !FindInMap [Map, CIDR, SubnetC]
MapPublicIpOnLaunch: true
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
SubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRouteTable
SubnetCRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref PublicRouteTable
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB security group
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Subnets:
- !Ref PublicSubnetA
- !Ref PublicSubnetC
SecurityGroups:
- !Ref ALBSecurityGroup
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ALB
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Port: 80
Protocol: HTTP
TargetType: instance
HealthCheckProtocol: HTTP
HealthCheckPort: 80
HealthCheckPath: /
SSMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
SSMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref SSMRole
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref LatestAmiId
InstanceType: !Ref InstanceType
SecurityGroups: [!Ref InstanceSecurityGroup]
IamInstanceProfile: !Ref SSMInstanceProfile
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
INSTANCE_ID=`curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-id`
AZ=`curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/placement/availability-zone`
echo "<h1>This is EC2 in $AZ</h1>" > /var/www/html/index.html
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref PublicSubnetA
- !Ref PublicSubnetC
LaunchConfigurationName: !Ref LaunchConfiguration
MinSize: !Ref DesiredCapacity
MaxSize: !Ref MaxCapacity
DesiredCapacity: !Ref DesiredCapacity
TargetGroupARNs:
- !Ref TargetGroup
Tags:
- Key: AutoScalingGroupName
Value: !Ref Project
PropagateAtLaunch: true
- Key: Name
Value: !Ref Project
PropagateAtLaunch: true
CPUAlarmHigh:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: "Alarm when CPU exceeds 75%"
Namespace: AWS/EC2
MetricName: CPUUtilization
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref AutoScalingGroup
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 75
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleOutPolicy
CPUAlarmLow:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: "Alarm when CPU is below 30%"
Namespace: AWS/EC2
MetricName: CPUUtilization
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref AutoScalingGroup
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 30
ComparisonOperator: LessThanThreshold
AlarmActions:
- !Ref ScaleInPolicy
ScaleOutPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: SimpleScaling
ScalingAdjustment: 1
AdjustmentType: ChangeInCapacity
Cooldown: 300
ScaleInPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: SimpleScaling
ScalingAdjustment: -1
AdjustmentType: ChangeInCapacity
Cooldown: 300
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow ALB access only
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
FISExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: FISExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: fis.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: FISSSMPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ssm:DescribeDocument
Resource: arn:aws:ssm:*:*:document/AWSFIS-Run-CPU-Stress
- Effect: Allow
Action:
- ec2:DescribeInstances
- ec2:DescribeInstanceStatus
- ssm:ListCommandInvocations
- ssm:ListCommands
- ssm:SendCommand
Resource: "*"
- Effect: Allow
Action:
- "iam:PassRole"
Resource: "*"
FISExperiment:
Type: AWS::FIS::ExperimentTemplate
Properties:
Description: Test Auto Scaling by stress cpu
RoleArn: !GetAtt FISExecutionRole.Arn
Actions:
StressCPU:
ActionId: aws:ssm:send-command
Parameters:
documentArn: !Sub arn:aws:ssm:${AWS::Region}::document/AWSFIS-Run-CPU-Stress
documentParameters: "{\"LoadPercent\":\"100\", \"DurationSeconds\":\"290\", \"InstallDependencies\":\"True\"}"
duration: PT5M
Targets:
Instances: oneRandomInstance
Targets:
oneRandomInstance:
ResourceType: aws:ec2:instance
ResourceTags:
AutoScalingGroupName: !Ref Project
SelectionMode: COUNT(2)
StopConditions:
- Source: none
Tags:
Name: fisStressCPU
Outputs:
LoadBalancerDNSName:
Value: !GetAtt ALB.DNSName
FISExperimentId:
Value: !Ref FISExperiment
保存したディレクトリで下記のコマンドを実行し、デプロイします。
rain deploy <保存したファイル名>.yaml <お好みのスタック名>
本ブログではスタック名は blog-fis としてデプロイします。
パラメータの確認が入りますが、変更は特に必要ありませんので、何も入力せずに Enter を押してください。
# rain deploy blog-fis.yaml blog-fis
Enter a value for parameter 'Project' (default value: blog-fis):
Enter a value for parameter 'LatestAmiId' (default value: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64):
Enter a value for parameter 'InstanceType' (default value: t3.micro):
Enter a value for parameter 'DesiredCapacity' (default value: 2):
CloudFormation will make the following changes:
Stack blog-fis:
+ AWS::ElasticLoadBalancingV2::Listener ALBListener
+ AWS::EC2::SecurityGroup ALBSecurityGroup
+ AWS::ElasticLoadBalancingV2::LoadBalancer ALB
+ AWS::EC2::VPCGatewayAttachment AttachGateway
+ AWS::AutoScaling::AutoScalingGroup AutoScalingGroup
+ AWS::CloudWatch::Alarm CPUAlarmHigh
+ AWS::CloudWatch::Alarm CPUAlarmLow
+ AWS::IAM::Role FISExecutionRole
+ AWS::FIS::ExperimentTemplate FISExperiment
+ AWS::EC2::SecurityGroup InstanceSecurityGroup
+ AWS::EC2::InternetGateway InternetGateway
+ AWS::AutoScaling::LaunchConfiguration LaunchConfiguration
+ AWS::EC2::RouteTable PublicRouteTable
+ AWS::EC2::Route PublicRoute
+ AWS::EC2::Subnet PublicSubnetA
+ AWS::EC2::Subnet PublicSubnetC
+ AWS::IAM::InstanceProfile SSMInstanceProfile
+ AWS::IAM::Role SSMRole
+ AWS::AutoScaling::ScalingPolicy ScaleInPolicy
+ AWS::AutoScaling::ScalingPolicy ScaleOutPolicy
+ AWS::EC2::SubnetRouteTableAssociation SubnetARouteTableAssociation
+ AWS::EC2::SubnetRouteTableAssociation SubnetCRouteTableAssociation
+ AWS::ElasticLoadBalancingV2::TargetGroup TargetGroup
+ AWS::EC2::VPC VPC
Do you wish to continue? (Y/n)
Deploying template 'blog-fis.yaml' as stack 'blog-fis' in ap-northeast-1.
デプロイ中は ターミナルからも進行状況を確認できますが、 AWS マネジメントコンソールの CloudFormation からもご確認いただけます。
デプロイが完了すると、 CREATE_COMPLETE と表示されます。
Outputs の FISExperimentId に表示される ID は後ほど使用するのでメモ帳などに控えておいてください。
Stack blog-fis: CREATE_COMPLETE
Outputs:
LoadBalancerDNSName: blog-fis-ALB-qcELvTVgdML6-949204421.ap-northeast-1.elb.amazonaws.com
FISExperimentId: EXT2AKuaB4k5fDVi
Successfully deployed blog-fis
Apache が動作しているか確認しましょう。
ブラウザを開き、Outputs の LoadBalancerDNSName に表示されている DNS を検索バーに入力してみます。
デプロイされる ALB には 2 台の EC2( ap-northeast-1a と ap-northeast-1c )が登録され、ラウンドロビンで振り分けられるようになっているので、ブラウザをリロードすると表示が切り替わることが確認できます。
AWS マネジメントコンソールの AutoScaling でもデプロイしたリソースを確認してみます。
デプロイした状態だと 2 台のインスタンスが起動している状態です。
2. AWS Fault Injection Simulator(FIS)で実験実行
それでは実際に AWS Fault Injection Simulator(FIS)で実験を実行してみましょう。
まずは AWS マネジメントコンソールで確認します。
ここで一つ落とし穴があります。
検索ボックスには “Fault Injection Simulator” ではなく、 “FIS” や “AWS FIS” と入力しないとサービスを見つけることができないのでご注意ください。
AWS マネジメントコンソールからでも実行できるのですが、今回は AWS CLI で実行します。
aws fis start-experiment --experiment-template-id <スタックデプロイ完了後に表示されるFISExperimentId> | jq -r '.experiment.id'
正常に実験が開始されました。本実験は 5 分間 AutoScalingGroup 内のインスタンス 2 台の CPU 負荷を上昇させます。
# aws fis start-experiment --experiment-template-id EXT2AKuaB4k5fDVi | jq -r '.experiment.id'
EXP8KURDeW4xBph3vA
出力される ID を AWS マネジメントコンソールの AWS FIS 画面の 回復力のテスト > 実験 で検索すると、実行中の実験を確認できます。
しばらくすると、スケールアウトのスケーリングポリシーが機能し、3 台目のインスタンスが起動しました。
ブラウザで確認するとラウンドロビンで ap-northeast-1a が 2 回表示されます。
実験完了後、しばらくするとスケールインのスケーリングポリシーが機能し、再び AutoScaling で起動しているインスタンスは 2 台の状態に戻ります。
本ブログの実験では、 AutoSacling が機能していることを確認することで完了としますが、実際に業務で利用する場合には、必要に応じてスケーリングポリシーを調整することで、システムのレジリエンスを向上させることができます。
AWS Fault Injection Simulator(FIS)を安全に導入するには
障害を意図的に起こすというとリスクが高いように感じるかもしれませんが、AWS Fault Injection Simulator(FIS)はそのプロセスを安全に管理するためのツールも備えています。
例えば、AWS Fault Injection Simulator(FIS)は実験を行う際に事前に「ガードレール」を設定することができます。これにより、影響範囲を最小限に抑え、重要なリソースやプロダクション環境に悪影響が及ばないようにコントロールできます。
本ブログでの説明は割愛しますが、ご興味があれば AWS 公式ドキュメント[*1]をご確認ください。
AWS Fault Injection Simulator(FIS)を使ってみた(まとめ)
AWS Fault Injection Simulator(FIS)は、システムの信頼性を確保し、障害に強いインフラを構築するための強力なツールです。企業にとって、意図的な障害をシミュレーションし、その対応力を高めることは、サービスの質の向上に繋がります。AWS Fault Injection Simulator(FIS)を使って、より堅牢で信頼性の高いクラウドインフラを実現してみませんか?
今回ご紹介した AWS Fault Injection Simulator(FIS)に限らず、「AWS でこんなことできないかな?」「自社サーバーを AWS に引っ越したいな。」等々ございましたら、右上の[お問い合わせ]からお気軽にご相談ください。
ご参考:ユーザーガイド(AWS)
*1「AWS FIS の停止条件」
https://docs.aws.amazon.com/ja_jp/fis/latest/userguide/stop-conditions.html
【筆者実行環境】
PC:MacBook Air (M1, 2020)
OS:macOS Sequoia 15.1
rain:Rain v1.17.0 darwin/arm64
aws cli:aws-cli/2.18.14 Python/3.12.7 Darwin/24.1.0 source/arm64
jq:jq-1.7.1
元記事発行日: 2025年01月08日、最終更新日: 2025年01月17日