AI、流行っていますね。 AWS Summit Japan 2024 のブースで展示されていた Failure Analysis Assistant を試してみましたので紹介します。
とりあえず環境構築
最近は CDK でサンプルコードが用意されおり、簡単にデプロイできるのがとても便利です。
前提条件を確認してとりあえずデプロイしてみます。
前提条件の確認
- AWS Cloud Development Kit (CDK) が利用できること
- 本サンプルは CDK で実装されています
手順に bootstrap 等は含まれていますが、CDK チュートリアルのステップ2, 3 は完了しておきましょう。
docs.aws.amazon.comdocs.aws.amazon.com
- 分析したいログが含まれている、CloudWatch Logs のロググループがあること
- 加えて、AWS CloudTrail、Application Load Balancer (ALB) のアクセスログを利用する場合、Amazon Athena のデータベースが作成されていること
- AWS X-Ray のトレース情報も利用する場合、該当システムの AWS X-Ray トレースが取得できていること
分析したいログ、つまり今回障害を試しに起こしてみるアプリケーションの CloudWatch ロググループが必要ですが、デプロイ後後から変更もできるのでとりあえず適当なロググループを一つ用意しとけばデプロイは可能です。
- Amazon Bedrock でモデルアクセスから、Claude 3 Sonnet, Claude 3.5 Sonnet のアクセス許可をしていること
- Claude 3.5 Sonnet は、Mermaid記法で画像による障害原因の仮説を図示するために利用します
現在 3.5 Sonnet は東京リージョンでも利用可能です。
どのモデルを使うかは後で出てくる手順で指定できますが、今回は Claude 3.5 Sonnet のみを使ってみたいと思います。
- 既存ワークロードで設定した AWS Chatbot から Slack にアラームの通知が来ることを確認していること
- FA2 のテスト利用のための既存ワークロードがない、もしくは利用できない場合、FA2のお試し環境の作り方を参考に、環境を作ることもできます
Slack に Chat が送信されたことをトリガーにして FA2 の動作が開始します。Chat が送信されてそれが AWS Chatbot なら…といった処理が Lambda で走るのでお使いの Slack チャンネルに AWS Chatbot が追加できるようにしておくとスムーズに検証できると思います。 ここは色々試しようがあるので、とりあえず検証用の Slack チャンネルを用意し、任意のアプリケーションが追加できるようにしておきます。
- 利用したい Slack ワークスペースに Slack App を登録できる権限を持っていること
記載のとおりです。
- Amazon API Gateway のコンソールで、CloudWatch ログ記録を有効にしていること
- 未設定の場合は、こちらの記事の[解決策]にある、[CloudWatch へのログ記録用の IAM ロールを作成する]と[API ゲートウェイコンソールに IAM ロールを追加する]を実施してください
マネジメントコンソールから以下のようにログ設定がを済ませておきます。
Slack アプリの登録
スクリーンショットを添付するので参考にしてください。
- Slack apiを開き、[create New App]をクリックします
2. [From scratch]を選び、App Name の入力と開発するときに使うワークスペースを選択し、[Create App]をクリックします
3. Slack apiに自分が作成したアプリが表示されるので、それを選択します 4. 左メニューの[Basic Information]をクリックし、[Signing Secret]を確認し、次のコマンドを実行し、Secrets Manager に登録します $ aws secretsmanager create-secret --name SlackSigningSecret --secret-string XXXXXXXXXXXXXXXXXXXXXXXX --profile {your_profile}
{ "ARN": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:SlackSigningSecret-xxxxxx", "Name": "SlackSigningSecret", "VersionId": "xxx" }
AWS CLI コマンド実行後、上記のように出れば登録は問題ないと思います。SlackSigningSecret
のところを任意の名前に変えてもよいですがその場合は名前を控えておきましょう。
5.左メニューの[OAuth & Permissions]をクリックし、[Scopes]で、channels:read, chat:write, files:writeを追加します
Slack アプリに「パブリック」チャンネルへの投稿読み取り、チャット・ファイルの書き込みを可能にします。パブリックというところが重要で、私はプライベートチャンネルで検証したため失敗していました。検証、動作させるチャンネルはパブリックチャンネルである必要があるので注意してください。
6. ページ上部の、[OAuth Tokens for Your Workspace]の[Install to Workspace]をクリックし、Slack Appをワークスペースにインストールします
7. リダイレクトされて戻ってきたページに[Bot User OAuth Token]が表示されるので、次のコマンドを実行し、Secrets Manager に登録します $ aws secretsmanager create-secret --name SlackAppToken --secret-string xxxx-1111111111111-1111111111111-XXXXXXXXXXXXXXXXXXXXXXXX --profile {your_profile}
CDK デプロイ
CDK のデプロイを行うのでサンプルコードをクローンします。
パラメータ設定
パラメータ固有の値を parameter.ts を新しく作って(parameter_template.ts をコピーして)設定します。 最低限のことをやる場合は以下のような感じで良いと思います。
export const devParameter: AppParameter = { env: { account: "xxxxxxxxxxxx", region: "ap-northeast-1", }, language: "ja", envName: "Development", modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0", slackAppTokenKey: "SlackAppToken", slackSigningSecretKey: "SlackSigningSecret", architectureDescription: "あなたが担当するワークロードは、Slack アプリとして API Gateway と Lambda DynamboDB で動作している WebSocket の チャットアプリケーションです。", cwLogsLogGroups: [ "/aws/lambda/chat-app-messagelambda16C1C2A3-BdaTOhCvh2fE", "/aws/lambda/chat-app-connectlambdaFFAE59F3-97MeW3OOSfde", "/aws/lambda/chat-app-disconnectlambdaAC22A441-Iylt7wFozXAR" ], // It's just sample query. Please you optimize to your situation. cwLogsInsightQuery: "fields @message | limit 100", //databaseName: "athenadatacatalog1111111", //albAccessLogTableName: "alb_access_logs", //cloudTrailLogTableName: "cloud_trail_logs", xrayTrace: false, slashCommands: { insight: false, findingsReport: false, }, // detectorId: "xxxxxxxxxxxxx" };
詳しい説明は README を参考にしてください。
項目 | 値 | 説明 |
---|---|---|
region | ap-northeast-1 | Bedrock のモデルも東京リージョンのものを使うのでこれを選択しています |
modelId | anthropic.claude-3-5-sonnet-20240620-v1:0 | 前提条件の手順で有効化したモデルを選択します |
architectureDescription | 略 | 何でも良いので記載します、障害を検知したいサービスの構成が分かり次第変更して構成をわかりやすく記載すると嬉しいことがあるでしょう |
cwLogsLogGroups | 略 | 何でも良いのですでに存在するロググループを選択してください(詳しい説明は後でします) |
デプロイ実行
bootstrap は実行済みであれば、改めて実行しなくても大丈夫です。
$ npm run build:layer // 障害原因の仮説を図示する機能を利用するために実施します $ npm install $ npx cdk bootstrap --profile {your_profile} $ npx cdk deploy --all --profile {your_profile} --require-approval never
アプリケーションと障害起動準備
環境の構築をひとまず完了できたので、障害を起こすアプリケーションを作ってみます。
構築するアプリケーション
CDK のサンプルコードを使います。 Web ソケットを使った API Gateway、Lambda × 3、Dynambo DB を使った簡単なチャットアプリケーションの構成です。
CDK でデプロイします。私がハマった点で、README > Deploy 部分に記載のある通り、config.json の account_id
部分をデプロイ先のアカウント ID に変更するのを忘れないようにしないとアプリケーションの実行が失敗します。(ついでにリージョンも)
Lambda 関数にアタッチする権限を作成している箇所でaccount_id
を参照しているため、空白のままだと対象の関数実行時にエラーがでます※ 私はこの部分のエラーも FA2 に解析してもらったので後ほど「おまけ」部分を参考ください。
デプロイ後、README の通りwscat をインストールし、アプリケーションが実行できれば成功です。
$ wscat -c wss://xxx.execute-api.ap-northeast-1.amazonaws.com/dev connected > {"action":"sendmessage", "data":"hello world"} < hello world
FA2 にアプリケーションを分析させる
先ほどとりあえずデプロイした FA2 の parameter.ts を修正して構築したアプリケーションに対して分析できるように変更します。
architectureDescription: "あなたが担当するワークロードは、Slack アプリとして API Gateway と Lambda DynamboDB で動作している WebSocket の チャットアプリケーションです。", cwLogsLogGroups: [ "/aws/lambda/chat-app-messagelambda16C1C2A3-BdaTOhCvh2fE", "/aws/lambda/chat-app-connectlambdaFFAE59F3-97MeW3OOSfde", "/aws/lambda/chat-app-disconnectlambdaAC22A441-Iylt7wFozXAR" ],
architectureDescription にはアーキテクチャの詳細を記載し、cwLogsLogGroups に動作している Lambda 関数のロググループを指定します。 再度 cdk deploy コマンドを実行します。
Chatbot にエラーメッセージを送信させる
このままの状態では FA2 は起動してくれません。「Slack に Chat が送信されたことをトリガーにして FA2 の動作が開始します」と記載した通り、アプリケーションのエラーで Chatbot が動くようにします。 サンプルで使えるものばかり流用していますがこれも以下サンプルを使います。
CloudFormation のテンプレートが用意されているので LambdaFunctionNames
にエラーを発生させたい(発生させたときに Chatbot に通知を上げたい)関数名を入れます。以下例ではchat-app-connectlambda...
を入力しています。(この Lambda 関数の実行を失敗させます)
複数の関数に対するエラーを Chatbot に通知させたい場合はタグで管理することもできるようです。 また、通知したい Slack の Workspace ID と Channnel ID を確認し、対象のチャンネルへ AWS Chatbot アプリをインストールします。
Slack アプリの修正
Slack アプリから FA2 アプリを呼び出せるように Slack アプリに追加設定を実施します。
1. CDK デプロイ後に、Amazon API Gateway のエンドポイント URL を確認します
cdk deploy 後のコマンドラインやマネジメントコンソールから確認できます。
2. Slack apiを開き、表示された画面の左メニューにある、[Interactivity & Shortcuts]を選択し、[Interactivity]を ON にしたあと、[Request URL]に 1 で確認した Amazon API Gateway のエンドポイントを入力し(例: https://{API Gateway のエンドポイント}/v1/slack/events)、[Save Changes]をクリックします API のリソース名は変更していなければ、例の通り、/slack/events となります
この設定により、Slack からボタンを押した際にこのエンドポイントへリクエストが送信されます。
3. 次に、左メニューの[Event Subscriptions]をクリックし、[Enable Events]を ON にしたあと、[Interactivity]と同様に、[Reqeust URL]を設定します
4. 同じ画面の[Subscribe to bot events]を開き、[Add Bot User Event]をクリックし、message.channels を追加し、[Save Changes]をクリックします
この設定により、チャンネルへメッセージが送信された時に対象エンドポイントへリクエストが送信されます。これによって Chatbot がメッセージを送信した時に FA2 アプリが起動することになります。
6. 対象のチャンネルへ Slack App を参加させます。追加するには、対象のチャンネルを開き、チャンネル名をクリックします。[インテグレーション]を選択し、[アプリを追加する]をクリックします。FA2(またはご自身が登録したアプリ名)を探し、[追加]ボタンをクリックします。表示される指示に従ってアプリをインストールします
記載の通り、Chatbot を送信しているチャンネルと同じチャンネルへ FA2 のアプリケーションをインストールします。
FIS でエラーを無理やり発生させる
AWS Lambda が AWS Fault Injection Service (FIS) アクションのサポートを開始したアップデートがあったのでこれを使ってみます。
Lambda Extensions の仕様が関わってきたり、準備も必要だったりするので、もしかしたらブログにするかもしれないです。 FIS の設定がめんどくさく、検証で使う場合は Lambda 関数のコードをいじってエラーでるようにすると楽です。
前準備
以下設定を済ませます。
- S3 バケットの作成
- ポリシーの作成(1. のバケットへの read/write アクセス)
- エラーを発生させたい Lambda 関数の IAM ロールへポリシーのアタッチ
- エラーを発生させたい Lambda 関数へ環境変数を追加
- エラーを発生させたい Lambda 関数へレイヤーを追加
実験テンプレート作成
実験テンプレートを作っていきます。
ターゲットから先に作ります。
- Resource type: aws:lambda:function
- Target method、Resource IDs: 「Chatbot にエラーメッセージを送信させる」で設定した関数を選択
次にアクションの追加です。
- Action type: 実行エラーを起こしたいので
aws:lambda:invocation-error
を選択します - Target: 上記で作成したターゲットを選択します
- Action parameters
- Duration: アクションの実行時間です、手動で止めることもできるので、検証時は少々長めでも問題ないと思います
- Invocation percentage: 関数は一つだけなので 100%です
- Prevent execution: 実行したくないので有効化します
EC2 などの実験テンプレートを作成する場合は「Create a new role for the experiment template」で IAM ロールを作成できるのですが、Lambda はできないので一から作る必要があります。
Use case に FIS があるので AWSFaultInjectionSimulatorEC2Access
など適当なものを選んで IAM ロールを作成します。
ポリシーには「前準備の2. 」で作成した S3 バケットへの wite 権限のポリシーを追加します。ドキュメントにはこっそり書いていました。 また、FIS のログを出力したい場合は CloudWatch Logs への書き込み権限を追加します(図は FullAccess ですみません)
オプション設定は何もなくて問題ないです、CloudWatch アラームで FIS を停止したい場合はアラームを、ログを出力したい時はロググループを選択します。
障害を起こす
ようやく FA2 を動かせます。
FIS 開始
まず、Lambda の実行が失敗するように作成した実験テンプレートを選び、 Start experiment から開始します。
「start」 と入力して開始です。 余談ですが、 AWS マネジメントコンソールからリソースを削除する時にリソース名や「delete」と入力することがあると思いますが、「start」は左手だけでタイピングできて楽ですよね。
数秒待って Status が Running になっていることを確認します。
wscat でアプリケーションに接続し、エラーが返ってくることを確認します。
$ wscat -c wss://xxx.execute-api.ap-northeast-1.amazonaws.com/dev error: Unexpected server response: 500
Lambda 実行エラーが発生したので Chatbot で通知が来ました。
Chatbot のチャットに反応して FA2 が起動し、入力フォームがでてきます。
通知の内容を入れて(画像では間違えてエラーの原因を入れてしまっています)発生したおおよその時間帯の範囲を選択し、「根本原因の分析を行う」を押下します。 しばらくすると、分析結果が返ってきました… 障害をわざと起こしたことがしっかりとバレていました、成功です。
かつ、そのSlack スレッドに障害がおきた場所の図が送られてきました。これは正直感動しました。
この図は parameter.ts に書いた architectureDescription
の内容を元に作成されているので AWS サービスの名前をしっかり書いてあげることでよりわかりやすくなると思います。今回でいうと Lambda 関数の数も書いてあげるとより良い図を作成してくれる気がします。
おまけ
Chat アプリケーションの構築に失敗した時
Chat アプリケーションの構築に失敗し、動作しなかった時の分析結果です。
AccessDeniedException と権限エラーの内容をしっかり教えてくれていますね。 障害図もどこで障害が発生したのかわかりやすく作ってくれました。
メンションで FA2 を起動させる方法
FA2 は Chatbot の通知によって起動していましたが中身がどうなっているのか気になってコードを調べてみました。 該当箇所は failure-analysis-assistant/lambda/functions/slack-handler/main.mts の以下の部分です。
app.message("", async ({ event, body, payload, say }) => { logger.info("message", {event: event, payload: payload, body: body}); // This ID is for AWS Chatbot app. // FA2 will return the form, when AWS Chatbot sent a message. // Please modify the condition by your environment. if ("app_id" in event && event.app_id === "A6L22LZNH") { const now = toZonedTime(new Date(), "Asia/Tokyo"); const res = await say({ blocks: messageClient.createFormBlock(format(now, "yyyy-MM-dd"), format(now, "HH:mm")), reply_broadcast: true } as SayArguments); logger.info('response', {response: res}); } });
このコードがどういうものかというと、Slack アプリで Subscribe to bot events に設定した message.channels により、チャンネルにメッセージが投稿されることでこの部分のコードが実行されます。
その後、event.app_id === "A6L22LZNH"
の条件分岐部分でそのメッセージを発したのが Chatbot かどうかを確認し、真であれば分析のためのフォームを送信する…といった内容になっています。
検証時分析フォームを出すために毎度 Chatbot の通知を出すのが面倒であり、対象チャンネルにメッセージが投稿されるたびに API Gateway を通して Lambda が実行されるのは料金的にあまり好ましくないと思ったため @アプリ名 で FA2 が分析フォームを出してくれるように改良しました。
app.event("app_mention", async ({ event, body, payload, say }) => { logger.info("message", {event: event, payload: payload, body: body}); const now = toZonedTime(new Date(), "Asia/Tokyo"); const res = await say({ blocks: messageClient.createFormBlock(format(now, "yyyy-MM-dd"), format(now, "HH:mm")), reply_broadcast: true } as SayArguments); logger.info('response', {response: res}); });
app.event("app_mention"
によりメンションで該当部分のコードが実行されます。
Chatbot アプリケーションかどうか否かの判定はいらないので条件分岐は削除します。
また、この変更をする場合に忘れてはならないのが Slack アプリの Subscribe to bot events をチャンネルにメッセーが投稿された時ではなく、アプリケーションがメンションされた時に起動するように app_mention に変更することです。
これによって @アプリ名で分析フォームを出してくれるようにできました。
※ アプリコードの改修は自己責任でお願いします。
まとめ
FA2、仕組みを理解した上で構築して分析させるのに結構苦労しました。 新しく追加された Lambda の FIS を使ったのもありますが、Chatbot による通知が必要であるなど使える場面は少々限られています。とはいえ、CDK でリソースの定義は全て行われており、用意されているコードを変更することで柔軟に対応はできそうだと思いました。
分析内容もしっかりしており、障害の原因や対象のログの箇所も教えてくれ、障害図から発生箇所もわかるため、導入さえしてしまえば料金もあまりかからない上に結構使えるツールであるのでは?というのが個人的な感想です。
末廣 満希(執筆記事の一覧)
2022年新卒入社です。ここに何かかっこいい一言を書くことができるエンジニアになれるように頑張ります。