AWS
CloudFormation

【AWS】CloudFormation Designer + 手直しで、VPCのテンプレート作成 【CloudFormation】

More than 1 year has passed since last update.

はじめに

こんにちは。
クラウドの魅力の一つと言えば、自動化ですよね。
文系学生からインフラエンジニアになって2年目となりますが、今後インフラエンジニアの仕事を奪われてしまうのではないかと、今からひやひやしています・・・

今回、「Infrastructure as Code」の触りとして、CloudFormationを使ってみようと思います。
ちなみに、コードは、まだまだ修行中です・・・

概要

CloudFormatinでネットワーク部分のテンプレートを作ります。
進め方としては、Designerを使い、ある程度の形を作り、それを修正していきます。

今回作成する構成
・VPC x 1
・パブリックサブネット x 2
・プライベートサブネット x 2
・ルートテーブル x 2
・インターネットゲートウェイ x 1

テンプレート作成

まず、Designerを使い、目的の構成のコードを作ります。
スクリーンショット 2015-12-23 11.51.58.png

この構成でコードを出力して中身を確認してみると、サービスとは関係なさそうなMetaDataがたくさんありました。
Designerを使って、テンプレートをつくるとDesignerの情報(位置情報等)もMetaData部分に入ってくるみたいです。
そのため、今回は、不要な部分の掃除もしました。

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

出力したコードから変更した点

・Designer向けの [MetaData] の削除
・論理IDをランダムのものから任意の値に変更
・[Properties] の編集及び追記 (Cidr、Tags、AZ等)
・IGWとVPCの関連付け
・ルートテーブルの作成(Public、Private)
・ルートテーブルとサブネットの関連付け

構文チェックは下記コマンドを実行することで可能です。(休日無くなるくらいには、エラーと戦いました!)
aws cloudformation validate-template --template-body <JSONファイル>

完成したJSONコード

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "myVPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
            "CidrBlock" : "10.0.0.0/16",
            "EnableDnsSupport" : "false",
            "EnableDnsHostnames" : "false",
            "InstanceTenancy" : "default",
            "Tags" : [ {"Key" : "Name", "Value" : "myVPC"} ]
         }
    },
    "myPublicSubnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {"Ref": "myVPC"},
        "CidrBlock" : "10.0.0.0/24",
        "AvailabilityZone" : "ap-northeast-1a",
        "Tags" : [ {"Key" : "Name", "Value" : "myPublicSubnet1"} ]
      },
      "DependsOn": [
          "myIGW"]
    },
    "mySubnetRouteTableAssociation1" : {
             "Type" : "AWS::EC2::SubnetRouteTableAssociation",
             "Properties" : {
                "SubnetId" : { "Ref" : "myPublicSubnet1" },
                "RouteTableId" : { "Ref" : "PublicRouteTable" }
             }
    },
    "myPublicSubnet2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "myVPC"
        },
        "CidrBlock" : "10.0.3.0/24",
        "AvailabilityZone" : "ap-northeast-1a",
        "Tags" : [ {"Key" : "Name", "Value" : "myPublicSubnet2"} ]
      },
      "DependsOn": [
        "myIGW"
      ]
    },
    "mySubnetRouteTableAssociation2" : {
             "Type" : "AWS::EC2::SubnetRouteTableAssociation",
             "Properties" : {
                "SubnetId" : { "Ref" : "myPublicSubnet2" },
                "RouteTableId" : { "Ref" : "PublicRouteTable" }
             }
    },
    "myPrivateSubnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "myVPC"
        },
        "CidrBlock" : "10.0.1.0/24",
        "AvailabilityZone" : "ap-northeast-1a",
        "Tags" : [ {"Key" : "Name", "Value" : "myPrivateSubnet1"} ]
      }
    },
    "mySubnetRouteTableAssociation3" : {
             "Type" : "AWS::EC2::SubnetRouteTableAssociation",
             "Properties" : {
                "SubnetId" : { "Ref" : "myPrivateSubnet1" },
                "RouteTableId" : { "Ref" : "PrivateRouteTable" }
             }
    },
    "myPrivateSubnet2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "myVPC"
        },
        "CidrBlock" : "10.0.2.0/24",
        "AvailabilityZone" : "ap-northeast-1c",
        "Tags" : [ {"Key" : "Name", "Value" : "myPrivateSubnet2"} ]
      }
    },
    "mySubnetRouteTableAssociation4" : {
             "Type" : "AWS::EC2::SubnetRouteTableAssociation",
             "Properties" : {
                "SubnetId" : { "Ref" : "myPrivateSubnet2" },
                "RouteTableId" : { "Ref" : "PrivateRouteTable" }
             }
    },
    "myIGW": {
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {}
    },
    "GWAttach": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "InternetGatewayId": {
          "Ref": "myIGW"
        },
        "VpcId": {
          "Ref": "myVPC"
        }
      }
    },
    "PublicRouteTable" : {
             "Type" : "AWS::EC2::RouteTable",
             "Properties" : {
                "VpcId" : { "Ref" : "myVPC" },
                "Tags" : [ { "Key" : "Name", "Value" : "PublicRouteTable" } ]
             }
    },
    "PublicRoute" : {
             "Type" : "AWS::EC2::Route",
             "Properties" : {
                "RouteTableId" : { "Ref" : "PublicRouteTable" },
                "DestinationCidrBlock" : "0.0.0.0/0",
                "GatewayId" : { "Ref" : "myIGW" }
             }
    },
    "PrivateRouteTable" : {
             "Type" : "AWS::EC2::RouteTable",
             "Properties" : {
                "VpcId" : { "Ref" : "myVPC" },
                "Tags" : [ { "Key" : "Name", "Value" : "PrivateRouteTable" } ]
             }
    }
  }
}

今回の反省点

・もっとDesignerで事前にサービスを追加しておけば、編集が必要な部分は減った。(AZ、ルートテーブルとか)
・そもそもJSONの仕組みを理解してないため、無駄なエラーが多かった。もっと勉強する。

さいごに

かなり悪戦苦闘しましたがなんとか動きました。
一から大規模なコードを書くとなるとかなり難しいのではないかと感じました。
ただ、Designerである程度コードを作ることで、私のような素人エンジニアでもCloudFormation使うことできることがわかりました。

今回書いたコードで個別の値の部分(論理ID、Cidr、Tags)とかは、スタックを作成する際に入力する形にしたいと思っています。(宿題)

修正が必要な部分などありましたら、ご連絡お願いします!
それでは、失礼します!