maya's blog

About programming, aws and ubuntu

AWS CloudFormation Nested Stackの作り方

AWS CloudFormation Logo
AWS CloudFormation

Purpose

分割したAWS CloudFormation(以下cfn)テンプレートからCfn Nested Stackを作成する。

Cfnを用いてVPCやSubnet、EC2 Instance、RDS等を1枚のテンプレートで宣言すると行数が多くなりテンプレートの見通しが悪くなる。 意味のある単位でファイル分割し、可読性を高める。

i.e. 以下のテンプレートに分割

  1. VPC, Subnet等のネットワーク
  2. ECSクラスタ
  3. RDS

テンプレート毎にstackを作成のであればテンプレートの枚数だけStack作成する必要があるし、依存関係を考慮して作成・削除する必要が出てくる。

そんな時にnested stackでテンプレートを構築・管理すれば楽になるよというお話。

What's Nested Stack

AWSのcfnドキュメント*1より抜粋。

ネストされたスタックは、他のスタックの一部として作成されたスタックです。ネストされたスタックは、AWS::CloudFormation::Stack リソースを使用して別のスタック内に作成します。

要するにcfn stackを作成する親stackが子stackを作成するということ。

以下実践例

Practice

ここでは親テンプレートとネットワーク用テンプレート(VPC, Subnet)の2枚を用いる。

Parent and Child Template

  • 親と子のテンプレートをそれぞれparent.yml, network.yml という名前にする。
  • 同ディレクトリに置く

parent.yml

AWSTemplateFormatVersion: '2010-09-09'

Resources:
  NetworkStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./network.yml

network.yml

AWSTemplateFormatVersion: '2010-09-09'

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.16.0.0/16
      EnableDnsSupport: 'false'
      EnableDnsHostnames: 'false'
      InstanceTenancy: dedicated

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ''
      CidrBlock: 172.16.0.0/24
      VpcId: !Ref VPC

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ''
      CidrBlock: 172.16.1.0/24
      VpcId: !Ref VPC

How to create Nested stack

parent.ymlPropertiesTemplateURLという項目があり、URLとあるので本来はS3へuploadした子テンプレートのURLを指定しなければいけない。 しかし、いちいち子テンプレートをS3にuploadして...とするのは面倒なので(子が増えれば尚更)。

そこでaws cloudformation packageコマンド*2を用いると便利。 aws cloudformation packageコマンドのオプションに親テンプレートとuploadするS3のbucket nameを指定し実行すると、

  1. 親と子のテンプレートを1つのファイルにしてbucketへupload
  2. 子テンプレートのURLに書き換えて親テンプレートを再定義

してくれる。stackを作成する際には再定義された2. のテンプレートを用いる。

AWS CLI

以下はコマンド例。やってることは

  1. aws cloudformation packageで親テンプレートを指定し、親と子テンプレートをbucketへupload
  2. aws cloudformation deployで1. で再定義された親テンプレートを用いてstackを作成

となっている。

./cfnディレクトリ配下にparent.yml, network.ymlがあるとする。

$ aws cloudformation package --template-file ./cfn/parent.yml --s3-bucket cfn-nested-template-demo --output-template-file /tmp/response.yml

Successfully packaged artifacts and wrote output template to file /tmp/response.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /tmp/response.yml --stack-name <YOUR STACK NAME>
$ aws cloudformation deploy --template-file /tmp/response.yml --stack-name nested-template-demo-stack

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - nested-template-demo-stack
$

package

1.の段階ではbucketにテンプレート1ファイルがuploadされる。

f:id:maya2250:20180623225413p:plain

再定義されたテンプレート(/tmp/response.yml)の内容は以下。子テンプレートを指定するURLが変わっている。

/tmp/response.yml

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  NetworkStack:
    Properties:
      TemplateURL: https://s3.amazonaws.com/cfn-nested-template-demo/49293d89d8ee829d742fb4bc4c522467.template
    Type: AWS::CloudFormation::Stack

deploy

2.が成功するとAWS Management ConsoleのCloudFormationでは以下のように確認できる。

  • 子テンプレートのstack名は親テンプレート名-子テンプレート名-ランダム文字列で与えられる。
  • AWS Management Console上では子テンプレートにNESTEDという便宜上のタグが表示される。

f:id:maya2250:20180623225935p:plain

Conclusion

  • CfnテンプレートをNested Stackで作成すると、複数枚テンプレートでAWS リソースを記述でき保守性が高まる
  • aws cloudformation package, aws cloudformation deployコマンドでNested Stackを作成しやすくする

余談になるけど、packageの標準出力をパイプで繋げてdeployに渡してワンライナーでできるかと思ったけれど、難しそう。

packageコマンドで--output-template-fileオプションを指定しなければ標準出力に再定義された親テンプレートを流してくれるけど、余計なメッセージ(Uploading to 49293d89d8ee829d742fb4bc4c522467.template 631 / 631.0 (100.00%)みたいなの)が含まれてできない。1行目を削除すればいけるか

子テンプレートをupdateしたいとか、子が他の子に依存している場合のupdateはどうなるかとかはまた別の記事でまとめたい。