CloudFormation Cross Stack Reference を用いたスタックの作り方


CloudFormation のテンプレートを分割した際のスタック作成・管理方法には Cross Stack Reference と Nested Stack の2通りあります。 そのうちの Nested Stack は 以前の記事 で紹介しました。 今回は Cross Stack Reference の紹介です。

Cross Stack Reference とは

Cross Stack Reference を用いると、スタック作成時に必要な情報を他の既存スタックから取得することができます。

実際に Cross Stack Reference を用いて CloudFormation テンプレートからスタックを作成してみましょう。

テンプレート

VPC, Subnet リソースを作成するテンプレートを用います。

vpc.yml

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: 10.0.0.0/16
Outputs:
  VPCId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub ${AWS::StackName}-VPCID

subnet.yml

AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  VPCStackName:
    Type: String
    Default: VPCCrossStackName

Resources:
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !ImportValue
        Fn::Sub: ${VPCStackName}-VPCID
      CidrBlock: 10.0.0.0/24

便宜上 vpc.yml, subnet.yml をそれぞれ親テンプレート、子テンプレート、 同様にそれらのテンプレートを用いて作成されたスタックもそれぞれ親スタック、子スタックと呼ぶことにします。

これらのテンプレートでは

  1. 親テンプレート: Outputs.Export.Name で参照名を指定
  2. 子テンプレート: Parameters でスタック名を渡し、 Fn::ImportValue 関数を用いて スタック名-VPCID で VPC ID を取得

としています。 ここでは子テンプレートのパラメタにスタック名を指定していますが、 親テンプレートでの出力値で指定した参照名を子テンプレートでそのまま用いても構いません。

スタック作成

実際に Cross Stack Reference を用いたスタックを作成してみましょう。

.
├── subnet.yml
└── vpc.yml

先と同じこれらのテンプレートを使います。

まずは親テンプレートから cross-stack-reference-vpc という名前のスタックを作成します。

$ aws cloudformation deploy --stack-name cross-stack-reference-vpc --template-file ./vpc.yml

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - cross-stack-reference-vpc

management-console-create-vpc-stack

作成できました。 マネコンからも cross-stack-reference-vpc-VPCID という出力値でエクスポートされていることが確認できました。

子テンプレートから cross-stack-reference-subnet という名前のスタックを作成します。

$ aws cloudformation deploy --stack-name cross-stack-reference-subnet --template-file ./subnet.yml --parameter-overrides VPCStackName=cross-stack-reference-vpc

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - cross-stack-reference-subnet

作成できました。

スタック更新

Cross Stack Reference を用いて作成されたスタックの更新にはいくつか注意が必要になります。

リソースを削除する必要のない更新は問題ありません。

diff --git a/vpc.yml b/vpc.yml
index 24f7529..87dca49 100644
--- a/vpc.yml
+++ b/vpc.yml
@@ -4,7 +4,7 @@ Resources:
     Type: AWS::EC2::VPC
     Properties:
       EnableDnsSupport: true
-      EnableDnsHostnames: true
+      EnableDnsHostnames: false
       CidrBlock: 10.0.0.0/16
 Outputs:
   VPCId:

このような親テンプレートは更新できます。

しかし、親テンプレートを更新時リソースを再作成する場合は他リソースが既に依存しているためエラーになります。 子スタックも自動で更新されることはありません。

今回では親テンプレートで VPC を削除し直す必要がある場合が当てはまります。

diff --git a/vpc.yml b/vpc.yml
index 24f7529..8d0402c 100644
--- a/vpc.yml
+++ b/vpc.yml
@@ -5,7 +5,7 @@ Resources:
     Properties:
       EnableDnsSupport: true
       EnableDnsHostnames: true
-      CidrBlock: 10.0.0.0/16
+      CidrBlock: 10.0.1.0/16
 Outputs:
   VPCId:
     Description: VPC ID

このように VPC CIDR を変更するには VPC の再作成が必要となり、 10.0.0.0/16 の VPC に既に依存している子リソースがあるのでエラーになります。 実際に更新してみると

Export cross-stack-reference-vpc-VPCID cannot be updated as it is in use by cross-stack-reference-subnet

という理由によりスタック更新が失敗しました。

この他にも親スタック更新が失敗する場合があるかと思われますので、しっかりと検証したほうが良いでしょう。

さいごに

今回は Cross Stack Reference を用いたスタックの作成・更新の仕方を紹介しました。

Nested Stack では子スタックの Change Set が確認できませんでしたが、Cross Stack Reference であれば可能です。 しかしデプロイは Cross Stack Reference の方が手間が掛かります。

この状況ではこっちのほうがいいと断言することはできませんが、 どこからどこまでを妥協・許容するのかによるのではないでしょうか。