【入門編】CloudFormationスタックのデプロイタイムアウトと失敗時の自動リトライ戦略:LambdaとStep Functionsを駆使した自作エラーハンドリング基盤 – インフラ構成管理(IaC)活用バイブル

CloudFormationのデプロイで「祈る」のはやめよう。Step Functionsで構築する堅牢なエラーハンドリング基盤

こんにちは。インフラエンジニアとして日々クラウドと格闘している皆さん、お疲れ様です。

CloudFormationでスタックを更新した際、「いつ終わるかわからない進捗バー」を眺めながら祈るような気持ちで過ごした経験はありませんか? 特に大規模な環境になると、リソースの依存関係やAPIのレート制限でタイムアウトが発生し、スタックが「ROLLBACK_FAILED」という悪夢のような状態で放置されることがあります。

今日は、そんな「IaCの運用ストレス」を根絶するための、AWSネイティブな自動エラーハンドリング基盤を設計しましょう。これをマスターすれば、デプロイは「祈るもの」ではなく「勝手に完了するもの」に変わります。

—

1. CloudFormation標準機能の限界:なぜ失敗するのか

CloudFormationには `TimeoutInMinutes` という設定がありますが、これはあくまで「構築の最大待ち時間」を定義するだけです。

  • 課題1:ロールバックの失敗: 依存関係が複雑な場合、ロールバック自体が失敗し、スタックが「手動介入が必要な状態」でフリーズします。
  • 課題2:運用の盲点: 通知設定(SNS)をしていても、エラー内容が抽象的で、「何が起きたか」を把握するためにコンソールをポチポチする時間が無駄になります。

我々SREが目指すべきは、「失敗を検知したら即座に状況を分析し、通知し、可能であれば自動復旧を試みる」というパイプラインです。

—

2. 設計図:Step Functionsを使った自律的デプロイ基盤

今回は、`CloudFormation → EventBridge → Step Functions → Lambda` という構成で、デプロイ失敗を自動ハンドリングする仕組みを作ります。

アーキテクチャの概要

1. EventBridge: CloudFormationのステータス変化(FAILED系)を検知。
2. Step Functions: 失敗時のワークフローを定義(通知 → ログ抽出 → 自動リトライ/ロールバック判断)。
3. Lambda: 具体的なデバッグ情報の抽出とSlackへの詳細レポート送信。

—

3. 実践:HelloWorld的な導入ステップ

まずは、「デプロイ失敗をトリガーにSlackへエラー内容を飛ばす」という最小構成から始めましょう。

Step 1: 失敗を検知するEventBridgeルールの定義

以下のパターンで、スタックが失敗した瞬間をキャッチします。

EventBridge Rule: CloudFormationFailureRule
EventPattern:
source:

  • “aws.cloudformation”

detail-type:

  • “CloudFormation Stack Status Change”

detail:
status-details:
status:

  • “ROLLBACK_FAILED”
  • “CREATE_FAILED”
  • “UPDATE_FAILED”

Step 2: 情報を抽出するLambda (Python)

スタックイベントから直近のエラー理由を抜き出し、整形して返す役割です。

import boto3
import json

def lambda_handler(event, context):
cfn = boto3.client(‘cloudformation’)
stack_name = event[‘detail’][‘stack-id’]

# 失敗したスタックのイベントを直近から取得
events = cfn.describe_stack_events(StackName=stack_name)[‘StackEvents’]
error_event = next((e for e in events if ‘FAILED’ in e[‘ResourceStatus’]), None)

# 現場で役立つ情報だけを抽出
error_reason = error_event.get(‘ResourceStatusReason’, ‘原因不明’)

return {
“stack_name”: stack_name,
“error_reason”: error_reason
}

Step 3: Step Functionsのワークフロー

ここが肝です。Lambdaの結果を受けて、Slackへ通知するフローを組みます。

{
“StartAt”: “ExtractError”,
“States”: {
“ExtractError”: {
“Type”: “Task”,
“Resource”: “arn:aws:lambda:…”,
“Next”: “NotifySlack”
},
“NotifySlack”: {
“Type”: “Task”,
“Resource”: “arn:aws:lambda:…”,
“Parameters”: {
“message”: “CloudFormationが爆発しました。原因: $.error_reason”
},
“End”: true
}
}
}

—

4. 現場で震えるほど役立つリトライ設計の極意

この基盤を作った後、次に考えるべきは「リトライ戦略」です。単にリトライすれば良いわけではありません。

1. 指数バックオフの採用: APIレート制限が原因の場合、即時リトライは逆効果です。Step Functionsの `Wait` 状態を使い、1分、5分、15分と間隔を空けてリトライさせるのがプロの作法です。
2. 冪等性の担保: IaCコードが「何度実行しても同じ結果になる」状態(冪等性)でなければ、リトライは恐怖の対象でしかありません。常に「一度削除して作り直す」のか「パッチを当てるのか」を明確にコード内で制御してください。
3. 「人間介入」の組み込み: 特定の深刻なエラー(例:クォータ上限到達)の場合は自動リトライを諦め、Slackのボタン一つで「ロールバック再試行」か「手動修復へ移行」かを選択させるUI(Interactive Messages)を組み込むと、運用チームから感謝されます。

まとめ:自動化は「信頼」をコードにする作業

CloudFormationのデプロイでエラーが起きても、「この仕組みが動いているから大丈夫」と心から思える状態。それこそがSREが提供すべき真の価値です。

まずは、皆さんの環境で「スタック失敗時にSlackに理由が飛ぶ」ところから始めてみてください。それだけで、監視画面を監視する無駄な時間から解放されますよ。

何か不明点があれば、遠慮なく聞いてくださいね。皆さんのインフラが、より堅牢で美しいものになることを応援しています。

タイトルとURLをコピーしました