Dev Study
AWSサービスの内部原理 コース

117. テンプレートは依存グラフ(DAG)である — Refが張る暗黙の辺と並列作成の順序

「リソースはどの順で作られるのか?」——この問いの答えが実はグラフ理論だという話を、テンプレートを頂点と辺の集まりに読み替えながら図で追っていきます。

① 参照を書くと、辺が1本張られる

テンプレートリソースを2つ宣言
依存する(!Refが張った辺)
MyEIPAWS::EC2::EIP
頂点になる
MyEC2InstanceAWS::EC2::Instance
頂点になる
  • 公式テンプレート例では MyEIP の Properties に InstanceId: !Ref MyEC2Instance と書く。この一行が「EIPはEC2インスタンスに依存する」という暗黙の依存(implicit dependency)を生む
  • 辺を張るのは !Ref だけではない。公式の言い回しは「target properties !Ref, !GetAtt, and !Sub」——プロパティの中でこの3関数のいずれかが他のリソースを指すと、辺が1本張られる

リソースは頂点、参照は辺。あなたは順序を書いていない——「AがBを参照している」という事実を書いただけで依存の辺は自動的に張られ、テンプレートは書いた瞬間に有向グラフになっている。

② 作成と削除で、辺を辿る向きが逆転する

作成(create)辺を「逆向き」に辿る
削除(delete)辺を「順向き」に辿る
完了してから
MyEC2Instance土台を先に作る
MyEIP上に載る方を先に消す
MyEIP依存先が無いと紐付けられない
MyEC2Instance土台を最後に消す
  • 公式の3つの規則(properties of A use a !Ref to B の場合): Resource B is created before resource A / Resource A is deleted before resource B / Resource B is updated before resource A(A=EIP、B=EC2)
  • 作成順と削除順は完全に逆。同じ1本の辺を、作成では逆向き・削除では順向きに辿る
  • 基礎への接続: これはスタック(データ構造)のLIFOそのもの。積み上げた逆順で取り崩す——関数呼び出しのコールスタックでもコンストラクタ/デストラクタの順序でも同じ「組み立てた逆順で分解する」原理

依存の辺は1本でも、辿る向きが作成と削除で反転する。だから「作る順」を覚える必要はない——グラフと「土台から積む/上から外す」という一つの原理があれば、両方が導ける。

③ 依存の無いリソースは、同時に走る(トポロジカル並列)

VPC波1: 同時に開始
S3Bucket波1: 同時に開始
どこにも依存しない孤立頂点は誰も待たない
!Ref — Subnetの完了を待つ
Subnet波2
EC2Instance波3
  • 公式の言い回し(そのまま): 「CloudFormation creates, updates, and deletes resources in parallel to the extent possible. It automatically determines which resources in a template can be parallelized and which have dependencies that require other operations to finish first.」
  • つまり「可能な限り並列」。辺で結ばれていないリソース(VPCとS3Bucket)は同じ波で同時に走り、辺で結ばれたリソースだけが相手の完了を待つ
  • 基礎への接続: makeやnpmのビルドグラフ、コンパイラの依存解決と完全に同じ問題。依存を辺として張れば、実行順序(トポロジカルソート)と並列できる箇所(同じ深さの頂点)が両方とも自動で導ける古典

順序はグラフから「導出」される。あなたが並列化の設計をしなくても、辺が無い頂点は勝手に同時に走る——宣言的な言語の旨味はここにある。

④ 参照が無いのに順序が要る場合 — DependsOn で辺を手で張る

EC2Instancepublic IP付き
GatewayToInternetVPCGatewayAttachment
参照は無い=暗黙の辺は張られない
作成順が確定する
DependsOn明示的な辺を手で張る
DependsOn: GatewayToInternet
道の開通が先アタッチメント完了→EC2作成。家を建てる前に道を通す
  • DependsOn は単一文字列でも文字列のリストでも取れる: DependsOn: GatewayToInternet あるいは DependsOn: [ ... ]
  • 公式必須ケース: 同一テンプレートに VPC と InternetGateway がある場合、public IP を持つ EC2・EIP・ELB・Auto Scaling グループ・RDS・IGWを含むVPCルートは、VPCゲートウェイアタッチメントへの DependsOn が必要
  • DependsOn は「override default parallelism」する道具でもある。参照から導けない制約を辺として手で追加し、デフォルトの並列を上書きする

参照はデータの依存(BのIDをAが使う)を辺にするが、現実には「データは要らないが順序は要る」制約がある。道が通る前に家を建てない——この暗黙の前提だけを DependsOn で明示的な辺として教える。

⑤ DependsOn の必須例をあと2つ — そして「要らない」対比

ECS::Service例A: ECSサービス
DeploymentGroup例B: CodeDeploy
対比: ポリシーをロールに埋め込むと
AutoScalingGroupコンテナインスタンスを揃える
IAM::Policyロールの権限を先に作る
無いと権限不足で作成失敗
埋め込みポリシーロールと同時に作成される
DependsOn 不要
  • ECS(公式): 「the Amazon ECS service resource must have a dependency on the Auto Scaling group or Amazon EC2 instances」——コンテナインスタンスをAuto Scalingで作る場合も、EC2インスタンスを直接並べる場合も、どちらもサービス側に辺を張る
  • IAM: ロールのポリシーは AWS::IAM::Policy または AWS::IAM::ManagedPolicy リソースで定義する。依存が無いと「the deployment group will fail to create because of insufficient permissions」。この依存は「ポリシーがリソースのライフサイクル全体で利用可能であること」を保証する
  • 対比(公式そのまま): 「If the role has an embedded policy, don't specify a dependency. CloudFormation creates the role and its policy at the same time.」——別リソースなら別頂点で辺が要るが、埋め込みポリシーは同じ頂点として同時に作られるので辺は不要

「別リソースに切り出すと辺が要る、埋め込むと同じ頂点で辺が要らない」——AWS::IAM::Policy と inline policy の違いは、そのまま「頂点を分けたか一つにまとめたか」の違い。DVAで「DependsOn はいつ必要か」が問われるのは、この頂点の切れ目を読めるかを試している。

⑥ 締め — 宣言的言語では「順序を書かない」

命令的Step FunctionsのFSM: 状態A→B→Cと順序を書く
宣言的CloudFormation: 制約(辺)だけ書く
導出できない暗黙の前提だけ
人間が明示次に何が起きるかを書く
グラフが導出トポロジカル順+並列を自動決定
DependsOn宣言的な世界に残った小さな命令的の窓
  • Step Functions編(FSM)は命令的: 状態遷移=次に何が起きるかを明示的に書く。CloudFormationは宣言的: 参照という事実を書くと順序はグラフから導出される。同じ「順序」でも、片方は宣言、片方は導出
  • DependsOn が補うのは、参照から導出できない制約(道の開通・権限の準備・インスタンスの充足)だけ
  • 基礎への接続: DAGとトポロジカルソートはビルド・コンパイラ・パッケージ解決を貫く一つの原理。テンプレートを読むときはYAMLの行の並びではなく、!Ref/!GetAtt/!Sub/DependsOn が張る辺を見て頭の中でグラフを描くのが正しい読み方

宣言的な言語で「順序を書かない」のは手抜きではなく設計思想。順序はグラフから導出されるものであり、導出できない暗黙の前提だけを DependsOn で教える——それが依存グラフとしてテンプレートを読む、ということ。

公式ドキュメントで詳しく ↗