[アップデート] AWS Fault Injection Service (FIS) が AWS Lambda にも障害アクションを発生出来るようになりました
いわさです。
AWS Fault Injection Service (FIS) では稼働しているワークロードに対して障害を発生させることが出来ます。
カオスエンジニアリングに使います。
EC2 や RDS を中心としたサービス + ネットワーク あたりでこれまでは障害を発生させることが出来ていたのですが、先日のアップデートでなんと Lambda 用の障害アクションが追加されました。
EC2 だと SSM、RDS であれば IAM を使って障害を発生させているので、まぁ FIS を使わなくてもやろうと思えば出来るアクションが多かったと思います。
Lambda で障害発生ってどう発生させているのでしょうね。気になります。
今回 SAM で作成したアプリケーションの一部の Lambda で FIS を使って遅延を発生させ、X-Ray トレースマップから障害発生の様子を確認までしてみましたので手順など紹介します。
AWS FIS で追加されたアクション
FIS で実験テンプレートを作成する際にアクションタイプを選択するのですが、新しく LAMBDA が追加され、その中に以下の 3 つのアクションが使えるようになっています。
やれるようになったことは 3 つで、指定した Lambda に対して呼び出し遅延の追加、エラーを発生、HTTP 統合時のレスポンスを上書きが出来るようになったみたいです。
各アクションや Lambda アクションの詳細については以下に記載されていまして、レスポンスストリーミングを使う関数では障害を発生させることが出来ないみたいです。
Lambda の レスポンスストリーミングについては以下などで紹介させて頂いたことがあります。Lambda から呼び出し元にTransfer-Encoding: chunked
の仕組みで断片的にレスポンスすることで Lambda のレスポンスサイズ上限などを超過させることが出来ます。
テスト用 SAM アプリケーションを作成
ここの手順は割愛しますが、SAM CLI を使ってテンプレートから API Gateway + Lambda + DynamoDB なサーバーレスアプリケーションをデプロイしました。
% sam init
% sam build
% sam deploy
次のように普通にレスポンスが取得出来る状態です。
% curl https://3cihrxkdh4.execute-api.ap-northeast-1.amazonaws.com/Prod/ -i
HTTP/2 200
content-type: application/json
content-length: 2
date: Thu, 31 Oct 2024 20:25:40 GMT
x-amzn-trace-id: Root=1-6723e7c4-2934fd943d98cf956eba3c0a
x-amzn-requestid: 98095b88-bbdf-4db3-849f-7d5cd9750ece
x-amz-apigw-id: AiEmvFp0NjMEiog=
x-cache: Miss from cloudfront
via: 1.1 c7f3213e2a3260f1c4aa8c8f7832ebbc.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-C3
x-amz-cf-id: 1oX61n0THTQEDzUQloVCJnT-L8ss3YhoXc-acjpmUXGpgd22Cdsf0A==
[]
実験テンプレートを作成する
では FIS の実験テンプレートを作成していきたいところなのですが、実験テンプレート作成前にいくつか前準備が必要です。このあたりは今までの障害アクションの中で一番設定が面倒かもしれません。
この Lambda で障害を発生させる仕組みなのですが、Lambda 関数に FIS 用のレイヤーをアタッチする必要があります。
そして FIS で実験が開始されると、設定した S3 バケットに障害アクション用のファイルが出力され、レイヤーがそれを参照して指定した挙動をしてくれるという仕組みです。
そのため実験テンプレート以外で以下が必要です。
- Lambda レイヤーと FIS が使う S3 バケットを作成
- Lambda レイヤーを関数に追加
- Lambda 実行ロールに S3 バケットへの読み取りポリシーを追加
- FIS サービスロールに S3 バケットへの書き込みポリシーを追加
手順は以下にも記載されています。
S3 バケット作成
まずは S3 バケットを作成します。
このバケットは複数の実験、複数の AWS アカウントで共有して使うことが出来ます。
読み取り・書き込みポリシーを追加して各ロールに設定
上記 S3 バケットに対して、Lambda からは読み取りを、FIS の実験からは書き込みを出来るようにします。
まず以下 2 つの IAM ポリシーを作成しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListingConfigLocation",
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::hoge-iwasa-fis-lambda"],
"Condition": {
"StringLike": {
"s3:prefix": ["FisConfigs/*"]
}
}
},
{
"Sid": "AllowReadingObjectFromConfigLocation",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": ["arn:aws:s3:::hoge-iwasa-fis-lambda/FisConfigs/*"]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowFisToWriteAndDeleteFaultConfigurations",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::hoge-iwasa-fis-lambda/FisConfigs/*"
},
{
"Sid": "AllowFisToInspectLambdaFunctions",
"Effect": "Allow",
"Action": [
"lambda:GetFunction"
],
"Resource": "*"
},
{
"Sid": "AllowFisToDoTagLookups",
"Effect": "Allow",
"Action": [
"tag:GetResources"
],
"Resource": "*"
}
]
}
で、IAM ロール(実験対象 Lambda 関数の実行ロール、FIS 実験テンプレートで設定したサービスロール)に上記ポリシーをそれぞれ設定します。
Lambda 関数にレイヤーを追加
つづいて障害アクションを実行するためのレイヤーを追加します。
レイヤーは AWS から提供されています。ARM と x86、あとはリージョンごとに ARN が異なるのでご注意ください。ARN は次のドキュメントに記載されています。
そして、先ほどの設定手順公式ドキュメントに記述があるのですが、AWS_FIS_CONFIGURATION_LOCATION
とAWS_LAMBDA_EXEC_WRAPPER
を環境変数に追加します。
こうしてみるとまぁまぁ Lambda 関数への変更が必要なことがわかりますね。
テンプレートを作成してみたが...
事前準備がようやく済みましたので、いよいよ実験テンプレートを作成してみましょう。
今回は Lambda 関数に 30000 ミリ秒の遅延を 5 分間発生させ、その間のサーバーレスアプリケーションの様子を観察してみます。
と、思いきや 1 ~ 1000 ミリ秒しか指定出来ないとコンソール上はエラーになってしまいました。
ドキュメント上では最大 900,000 ミリ秒まで指定出来るはずだが...
リリース直後のコンソールの不具合だろうと思い、今回は AWS CLI を使ってテンプレートを作成しました。こちらは無事作成が出来ました。
% cat hoge.json
{
"description": "hoge1101lambda",
"targets": {
"Functions-Target-1": {
"resourceType": "aws:lambda:function",
"resourceArns": [
"arn:aws:lambda:ap-northeast-1:123456789012:function:hoge1101fis-putItemFunction-FgwCZTFLrUwe"
],
"selectionMode": "ALL"
}
},
"actions": {
"hoge1101lambda": {
"actionId": "aws:lambda:invocation-add-delay",
"description": "hoge1101lambda",
"parameters": {
"duration": "PT5M",
"invocationPercentage": "100",
"startupDelayMilliseconds": "30000"
},
"targets": {
"Functions": "Functions-Target-1"
}
}
},
"stopConditions": [
{
"source": "none"
}
],
"roleArn": "arn:aws:iam::123456789012:role/iwasa-fis",
"tags": {
"Name": "hoge1101lambda2"
},
"experimentOptions": {
"accountTargeting": "single-account",
"emptyTargetResolutionMode": "fail"
}
}
% aws-v1 fis create-experiment-template --cli-input-json file://hoge.json
実験開始
長かったですが、いよいよ実験開始です。
無事ステータスが Running になりました。ここでエラーになる場合は Lambda 周りの設定などをもう一度確認してみてください。私は実行ロールへのポリシーアタッチが抜けていたりしました。
上記実験が開始されると、S3 バケット上に次のようなファイルが出力されます。
これを Lambda 関数がレイヤー経由で読み取って障害のインジェクションが行われるようですね。
中身はただの JSON ファイルで、実験テンプレートで設定した障害アクションの詳細情報が設定されていました。
{
"faults": [
{
"actionId": "aws:lambda:invocation-add-delay",
"parameters": {
"invocationPercentage": "100",
"startupDelayMilliseconds": "30000",
"qualifier": "$ANY",
"minimumRequiredExtensionVersion": "1.0.0"
},
"expiration": 1730511416536,
"startTime": 1730511315172
}
]
}
で、cURL でサーバーレスアプリケーションへリクエストを送信してみると...
% curl https://3cihrxkdh4.execute-api.ap-northeast-1.amazonaws.com/Prod/ -i
HTTP/2 504
content-type: application/json
content-length: 41
date: Fri, 01 Nov 2024 04:44:03 GMT
x-amzn-trace-id: Root=1-67245c76-2bf4ce3f15a87fff2d295f63
x-amzn-requestid: 900b42de-49d9-4107-93ae-c942e7195c62
x-amzn-errortype: InternalServerErrorException
x-amz-apigw-id: AjNijGA-tjMECCg=
x-cache: Error from cloudfront
via: 1.1 b8a08c0d748faf705ea0429a0bc6145c.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-C3
x-amz-cf-id: 9pvntNL1oBg8WqFf4Ka-fQ29BN7bemqxjfPNtkcH4b-N3Q-hPaKEQQ==
{"message": "Endpoint request timed out"}
おー、リクエストタイムアウトのエラーになりましたよ。これは良さそう。
X-Ray のトレースも確認してみましょう。
Lambda 関数で 30 秒以上かかり、API Gateway がエラーステータスとなっていることが確認出来ました。
さいごに
本日は AWS Fault Injection Service (FIS) が AWS Lambda にも障害アクションを発生出来るようになったので試してみました。
いやぁ今まで何度も FIS を触ってきましたが、一番事前準備が面倒でした。
関数構成に追加が必要だったりするので、そのあたりは導入にあたって注意しましょう。
ただ、一度設定出来ればサーバーレスマイクロサービスなんかで部分的な障害を発生させたり、外部 API への呼び出し部分で擬似的な遅延を再現したり色々出来そうで重宝しそうです。