こんにちは。インフラの深淵を覗き込み、数多のシステム障害をコードで解決してきたSREエンジニアです。
今日は、AWS CloudFormationを使い始めた多くのエンジニアが一度は遭遇し、そして立ち尽くす「循環依存(Circular Dependency)」という壁についてお話しします。
「スタックAがスタックBの出力を参照し、スタックBがスタックAの出力を参照する」。この状態に陥ると、スタックの更新も削除もできなくなり、インフラが「手出し無用のブラックボックス」と化します。
今日はこの泥沼から脱出し、疎結合で堅牢なインフラを構築するための「究極の設計パターン」を伝授します。
—
1. なぜ「循環依存」は発生するのか?(本質を理解する)
CloudFormationの `Export` と `Fn::ImportValue` は非常に強力ですが、これらは「強固な結合」を強います。
- 依存関係の可視化: スタックAがスタックBの値をインポートしている場合、スタックBを削除しようとすると「他のスタックから参照されているため削除できません」というエラーが出ます。
- 循環の罠: AがBを参照し、BがAを参照すると、どちらのスタックも更新・削除の順序を決定できなくなり、デプロイメントパイプラインは完全に停止します。
これは、あなたが書いたコードが「密結合」になっているという、設計上のシグナルです。
—
2. 疎結合への移行:SSM Parameter Storeによる「脱・依存」
循環依存を断ち切るための最も強力な武器は、AWS Systems Manager (SSM) Parameter Store です。
`ImportValue` は「直接参照」ですが、SSMは「名前解決」です。スタックAは「Bの詳細は知らないが、SSMにあるこのキーの値を読みに行く」という挙動に変わります。これにより、スタック間の物理的な依存関係が切断されます。
ステップ1:値をSSMに書き出す(提供側)
まず、スタックB(提供側)のテンプレートを修正します。
提供側のスタック(例: Network Stack)
Resources:
MyVpcIdParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /my-app/vpc-id # 一意のパスで名前を付ける
Type: String
Value: !Ref MyVpc # VPC IDをSSMに保存
ステップ2:SSMから値を読み取る(利用側)
次に、スタックA(利用側)で `ImportValue` を捨て、SSMから動的に取得します。
利用側のスタック(例: App Stack)
Parameters:
VpcId:
Type: AWS::SSM::Parameter::Value
Default: /my-app/vpc-id # ここで疎結合に参照!
Description: SSMからVPC IDを注入する
これで、スタック同士は物理的に結びつかず、SSMという「共通の辞書」を介して通信するようになりました。
—
3. リファクタリングの安全な移行手順(現場の鉄則)
いきなり全てを書き換えると事故が起きます。以下の「3段階移行法」を守ってください。
1. 二重書き込みフェーズ: 既存の `Export` を残したまま、新しい SSM Parameter を作成します。まだスタックAは `ImportValue` を使い続けます。
2. 参照切り替えフェーズ: スタックAを修正し、`ImportValue` から SSM 参照へ切り替えます。
3. クリーンアップフェーズ: 全ての参照が切れたことを確認してから、古い `Export` を削除します。
—
4. 基礎セットアップ:まずはここから始めよう
もし、これからCloudFormationを触るというなら、以下の「黄金の構成」から始めてください。
1. インストール不要: AWS CLIがインストールされた環境があれば、`aws cloudformation deploy` コマンドだけで完結します。
2. HelloWorld的な動作確認: 以下のYAMLを `template.yaml` として保存し、デプロイしてみましょう。
AWSTemplateFormatVersion: ‘2010-09-09’
Description: SRE流・疎結合の第一歩
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub “my-awesome-app-bucket-${AWS::AccountId}”
Outputs:
BucketName:
Value: !Ref MyBucket
Export:
Name: !Sub “${AWS::StackName}-BucketName” # 最初のうちはExportでOK
実行コマンド:
aws cloudformation deploy \
–template-file template.yaml \
–stack-name my-test-stack
—
先輩エンジニアからのアドバイス
「依存関係」は、システムが成長すればするほど複雑になります。最初から完璧な構成を目指す必要はありませんが、「何かを変えるときに、他のスタックを壊すリスクはないか?」と常に自問自答してください。
SSM Parameter Storeへの移行は、少し手間がかかるように感じるかもしれません。しかし、大規模なシステムにおいて「スタックを切り離せる」という状態は、あなたに圧倒的な安心感と、デプロイの自由を与えてくれます。
この設計をマスターすれば、どんな複雑なインフラでも恐れることはありません。さあ、次はあなたの番です。コードで、インフラを自由に操りましょう。