CloudFormation入門-ネットワーク環境の作成と組み込み関数-

ご機嫌いかがでしょうか、豊崎です。

先日CloudFormationの肩慣らし記事を書きました。

CloudFormation入門-ちいさな構成をつくって肩慣らし-

今回は先日作成したstackを更新してリソースを追加していきたいと思います。

準備

環境にリソースを追加する前にCloudFormationの組み込み関数を押さえておきましょう。

CloudFormationを実行するまでわからない値をプロパティに代入するために組み込み関数は使用されます。 今回は「Ref」,「!GetAtt」のみの利用で対応できる内容にしています。

  • Fn::Base64
  • 条件関数
  • Fn::FindInMap
  • Fn::GetAtt
  • Fn::GetAZs
  • Fn::ImportValue
  • Fn::Join
  • Fn::Select
  • Fn::Sub
  • Ref

組み込み関数について詳しくは弊社のブログをご参照ください。

AWS CloudFormation テンプレートリファレンス – 組み込み関数(Intrinsic Function)

CloudFormationのスタック間でリソースを参照する

CloudFormationの条件関数を利用する

作成する内容

web3層構造のネットワーク部分の環境とDataSubnetからインターネット通信をするためのNATGatewayを作成します。

*作成したテンプレートを実行すると課金が発生しますので、各自ご判断の上実施ください!!

  • VPC(前回作成済み)
  • InternetGateway
  • NATGateway
  • FrontSubnet(1a/1c)
  • AppSubnet(1a/1c)
  • DataSubnet(1a/1c)
  • PublecRouteTableFrontRoute(Front)
  • PrivateRouteTableDataRoute(App/Data)

CloudFormationテンプレート

###
AWSTemplateFormatVersion: "2010-09-09"

Resources:
### Create VPC
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      InstanceTenancy: default
      Tags:
       - Key: Name
         Value: MyVPC
# ここからが今回の内容です
### CreateInternetGateway
#### InternetGateway
  MyIGW:
    Type: "AWS::EC2::InternetGateway"
    Properties:
     Tags:
     - Key: Name
       Value: IGW
#### AttacheInternetGatewayToVPC
  MyIGWAttachVPC:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref MyIGW
      VpcId: !Ref MyVPC
# 組み込み関数の「!Ref」を使用してリソース名を取得しています

### CreateNATGateway
#### Elastic IP for NatGateway
  MyEIPforNATGW:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc
#### NatGateway
  MyNATGW:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId:
        !GetAtt MyEIPforNATGW.AllocationId
# 組み込み関数の「!GetAtt」を使用してリソースの属性を取得しています
      SubnetId:
        !Ref MyFrontSubnet1a

### CreateSubnet
#### FrontSubnet1a
  MyFrontSubnet1a:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.0.0/24
      MapPublicIpOnLaunch: true
      Tags:
      - Key: Name
        Value: MyFrontSubnet1a
#### FrontSubnet1c
  MyFrontSubnet1c:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      Tags:
      - Key: Name
        Value: MyFrontSubnet1c
#### MyAppSubnet1a
  MyAppSubnet1a:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.10.0/24
      MapPublicIpOnLaunch: false
      Tags:
      - Key: Name
        Value: MyAppSubnet1a
#### MyAppSubnet1c
  MyAppSubnet1c:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: 10.0.11.0/24
      MapPublicIpOnLaunch: false
      Tags:
      - Key: Name
        Value: MyAppSubnet1c
#### MyDataSubnet1a
  MyDataSubnet1a:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.20.0/24
      MapPublicIpOnLaunch: false
      Tags:
      - Key: Name
        Value: MyDataSubnet1a
#### MyDataSubnet1c
  MyDataSubnet1c:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref MyVPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: 10.0.21.0/24
      MapPublicIpOnLaunch: false
      Tags:
      - Key: Name
        Value: MyDataSubnet1c

###CreateRouteTable
#### MyPublicRouteTable
  MyPublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref MyVPC
      Tags:
      - Key: Name
        Value: MyPublicRouteTable
  RouteAddInternet:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref MyIGW
      RouteTableId: !Ref MyPublicRouteTable
  AssociateMyFrontSubnet1aToMyPublicRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPublicRouteTable
      SubnetId: !Ref MyFrontSubnet1a
  AssociateMyFrontSubnet1cToMyPublicRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPublicRouteTable
      SubnetId: !Ref MyFrontSubnet1c
#### MyPrivateRouteTable
  MyPrivateRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref MyVPC
      Tags:
      - Key: Name
        Value: MyPrivateRouteTable
  RouteAddNATGateway:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref MyNATGW
      RouteTableId: !Ref MyPrivateRouteTable
  AssociateMyAppSubnet1aToMyPublicRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPrivateRouteTable
      SubnetId: !Ref MyAppSubnet1a
  AssociateMyAppSubnet1cToMyPublicRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPrivateRouteTable
      SubnetId: !Ref MyAppSubnet1c
  AssociateMyFrontSubnet1aToMyPrivateRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPrivateRouteTable
      SubnetId: !Ref MyDataSubnet1a
  AssociateMyFrontSubnet1cToMyPrivateRouteTable:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref MyPrivateRouteTable
      SubnetId: !Ref MyDataSubnet1c

ChangeSet(更新箇所の確認)

上記のCloudFormationテンプレートを任意の名前で保存してAWSCLIから更新リソースの確認をします。 ChangeSetはアップデートを実行する前にどのような変更が加えられるかを簡易的に確認することができる機能です。 それでは実際に行いましょう。

$ aws cloudformation create-change-set
  --stack-name cm-vpc
  --change-set-name cm-updatestack1
  --template-body file://cloudformation-update1.yml
### 実際には1行です。
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXX:stack/cm-vpc/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "Id": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/cm-updatestack1/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX"
}
$ aws cloudformation describe-change-set
  --change-set-name cm-updatestack1
  --stack-name cm-vpc
### 実際には1行です。
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXX:stack/cm-vpc/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "Status": "CREATE_COMPLETE",
    "ChangeSetName": "cm-updatestack1",
    "Changes": [
        {
            "ResourceChange": {
                "Action": "Add",
                "ResourceType": "AWS::EC2::SubnetRouteTableAssociation",
                "Scope": [],
                "Details": [],
                "LogicalResourceId": "AssociateMyAppSubnet1aToMyPublicRouteTable"
            },
            "Type": "Resource"
        },
        ・
        ・中略
        ・
        {
            "ResourceChange": {
                "Action": "Add",
                "ResourceType": "AWS::EC2::Route",
                "Scope": [],
                "Details": [],
                "LogicalResourceId": "RouteAddInternet"
            },
            "Type": "Resource"
        }
    ],
    "CreationTime": "2017-03-19T02:54:31.281Z",
    "Capabilities": [],
    "StackName": "cm-vpc",
    "NotificationARNs": [],
    "ExecutionStatus": "AVAILABLE",
    "ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/cm-updatestack1/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX"
}

今回はリソースの追加だけなので、Actionが「Add」となっていますが、「Modify」、「Remove」があります。 また、Actionが「Modify」の時、リソースの置き換え(作り直し)が発生するかどうかをReplacementで教えてくれます。

コマンドで実行しましたが、もちろんAWSメネジメントコンソールで実行することも可能です。 その場合は以下のように表示されます。さすがにGUIの方がわかりやすいですね。

スクリーンショット 2017-03-20 8.26.50

UpdateStack(実際の更新)

それでは前回作成したStack(VPCのみ)を更新してネットワーク環境を作成しましょう。

*繰り返しになりますが、上記CloudFormationテンプレートを実行すると課金が発生します。

$ aws cloudformation execute-change-set
  --change-set-name cm-updatestack1
  --stack-name cm-vpc
### 実際には1行です。

CloudFormation_Management_Console

さいごに

今回作成したCloudFormationテンプレートでネットワーク環境が作成できます。 ここまで作ってしまえば好きなようにサブネット内にEC2などを構築することができます。 またyaml形式で記載することでコメントの記載や、リソースのブロックごとに行間を開けるなど可読性も高まりますね。

参考

AWS リソースプロパティタイプのリファレンス