CloudFormationでネストされたスタックを作成してみる

検証用のAWSリソースの作成/管理を行うためにネストされたスタック作成しましたので手順についてまとめます。
2021.01.26

こんにちは。クラメソにジョインして2年目になりました下地です。昨年はAWS CLIの操作に興味を持ち弊社の検証環境にて様々なリソースを作成しながらAWSについて学分ことができました。しかし、リソースを作り過ぎて管理工数がかかってしまいました。そこで自作のリソース管理を行うためCloudFormation(cfn)を使用していこうと思います。

1. はじめに

cfn使用時は各リソース(EC2やRDSなど)を別々のテンプレートに記述して管理するためにネストしたスタックを作成していきます。こちらのサイトを参考にVPCとSGを作成していきます。

2. テンプレートを作成する

今回は以下図のようにルートテンプレートを含む3つのテンプレートを作成します。

2.1 ルートスタックテンプレート

ルートテンプレート(root-stack.yaml)は以下のようになります。

root-stack.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: Manage myself verification environment

Parameters: 
  TemplateVPC:
    Description: VPC template Object URL
    Type: String
    Default: VPCtemplateのURLを記述

  TemplateSG:
    Description: SG template Object URL 
    Type: String
    Default: SGtemplateのURLを記述

Resources:
  # VPCの作成
  VPC:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Ref TemplateVPC
      Parameters:
        AZ1: !Select [0, !GetAZs '' ]
        CIDRBlock: '10.0.0.0/16'
        PublicSubnet1CIDR: '10.0.10.0/24'

  # SGの作成
  SG:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Ref TemplateSG
      Parameters: 
        VPCId: !GetAtt VPC.Outputs.VPCId
    DependsOn: VPC

Outputs:
  VPCId:
    Value: !GetAtt VPC.Outputs.VPCId
    Description: VPC CIDR Block

  PublicSubnet1Id:
    Value: !GetAtt VPC.Outputs.PublicSubnet1Id
    Description: PublicSubnet1 CIDR Block

  SSHHTTPSG:
    Value: !GetAtt SG.Outputs.SGSshHttp
    Description: SG for ssh and http

2.2 VPCテンプレート

ルートテンプレートから参照されるVPCテンプレート(vpc.yaml)の作成を行います。作成する内容はこちらのサイト(AWS CloudFormation VPC テンプレート)も参考に作成しました。

vpc.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: Provision of VPC

# パラメータ
Parameters:
  AZ1:
    Type: String
    Description: Use AZ name
  CIDRBlock:
    Type: String
    Description: CIDRBlock of VPC
  PublicSubnet1CIDR:
    Type: String
    Description: CIDRBlock of PublicSubnet1

Resources:
  # VPCの作成
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref CIDRBlock

  # IGWの作成
  IGW:
    Type: AWS::EC2::InternetGateway
    DependsOn: VPC

  # IGWをVPCにアタッチ
  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW
  
  # Public Subnetの作成
  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Ref AZ1
      CidrBlock: !Ref PublicSubnet1CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Ref AZ1

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  
  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: IGWAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW
  
  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  NoIngressSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "no-ingress-sg"
      GroupDescription: "Security group with no ingress rule"
      VpcId: !Ref VPC

Outputs:
  VPCId:
    Value: !Ref VPC
    Description: VPC id

  PublicSubnet1Id:
    Value: !Ref PublicSubnet1
    Description: Subnet1 id

2.3 SGテンプレート

ルートテーブルから参照されるSGテンプレート(sg.yaml)を作成します。

sg.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: Provision of EC2

# パラメータ
Parameters:
  VPCId:
    Type: String
    Description: ID for VPC.

Resources:
  SGSshHttp:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow SSH and HTTP access only MyIP
      VpcId: !Ref VPCId
      SecurityGroupIngress:
        # http
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: '0.0.0.0/0'
        # ssh
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: '0.0.0.0/0'

Outputs:
  SGSshHttp:
    Value: !Ref SGSshHttp
    Description: SGSshHttp id

3. ネストしたスタックを作成する

ではテンプレートを元にリソースを作成していきます。

3.1 VPCとSGテンプレートをS3にアップロード

VPCとSGのテンプレートは以下のように、child_stack_templateフォルダに配置しています。

tree
.
├── child_stack_template
│   ├── sg.yaml
│   └── vpc.yaml
└── root-stack.yaml

まずは子テンプレートのフォルダをs3 cpコマンドを使用してS3にアップロードします。

$ aws s3 cp child_stack_template s3://バケット名/ --recursive 
upload: child_stack_template/vpc.yaml to s3://バケット名/child_stack_template/vpc.yaml
upload: child_stack_template/sg.yaml to s3://バケット名/child_stack_template/sg.yaml

3.2 ルートテンプレートをアップロード

アップロード完了後、cfnのコンソール画面からネスとしたスタックを作成していきます。

  1. step1: テンプレートの指定
  2. スタックの作成を選択し、ルートテンプレート(root-stack.yaml)をアップロードして次に進みます。

  3. step2: スタックの詳細を指定
  4. スタックの名前をつけます。そして、VPCとSGの各テンプレートのオブジェクトURLを記載して次へ進みます。

  5. step3: スタックオプションの設定
  6. タグ名は任意ですので記入せずに次に進みます。

  7. step4: レビュー項目の設定
  8. コンソールの下のほうにある確認ボックスにチェックを入れてスタックの作成をクリックします。

3.3 スタック作成確認と削除

少し待つと「CREATE_COMPLETE」と表記され作成は完了です。子スタックであるVPCとSGテンプレートは「ネストされた」と表示されています。
出力項目には、root-stack.yamlのOutputsで指定した内容が表示されています。

リソースが作成されたことを確認できたら、ルートスタックの項目から削除します。削除するとネストされたスタックも一緒に削除されます!

4. まとめ

作成したリソースを管理するためにネストしたスタックを作成してみました。これまでcfnは使っていなかったので実装時には苦労しましたがスタックを削除するとすべてのリソースが削除されるので管理が簡易的になるなと実感しました。今後は今回作成したスタックをベースに必要なリソースのテンプレートを作成して検証環境を育てていけたらなと思います。

参考リンク