【はじめに】
AWS認定試験(特にAWS-DVA)の勉強をしていると、「Infrastructure as Code」というキーワードが出てきます。
Infrastructure as Code は、ITインフラ構築・運用をコードで管理することを言います。
人の手によってインフラ構築・運用が行われると人為的ミス、工数が増えコストが上がるなどの問題がありますが、Infrastructure as Codeで自動化すれば、ミスやコストの削減につながります。
AWSでは「AWS CloudFormation」を使用して実現することができます。
今回は、以前に解説したネットワーク環境の構成をAWS CloudFormationを利用して構築していきたいと思います。
コードをまるごと公開するので、是非試してみてください。
本記事の内容
- 構築するネットワーク構成図
- 実際にAWS CloudFormationを利用してネットワーク環境を構築する
- CloudFormationでスタックを作成する
- 作成したリソースを確認する
【構築するネットワーク構成図】
今回、構築するネットワーク構成図は以下となります。
また、構築するにあたって必要な項目と値を決めます。
【実際にAWS CloudFormationを利用してネットワーク環境を構築する】
今回はJSONでテンプレートを作成しました。
まるごとコードを公開します。
AWS CloudFormationテンプレート
jsonではYAMLとは違いファイルにコメントを残すことが出来ないみたいですが、今回は直接コメントを書いてしまいます。
(※コピペする場合は、コメントは消してください。)
{
// AWSTemplateFormatVersion(必須)
// 最新のテンプレートの形式バージョンを指定します。
↓
"AWSTemplateFormatVersion" : "2010-09-09",
// Description(オプション)
// 作成するテンプレートの説明を書きます。
↓
"Description" : "Create VPC, Subnet, Gateway, RouteTable",
// Metadata(オプション)
// AWS CloudFormationコンソールに表示される場合の入力パラメーターのグループ化と順序を定義します。
↓
"Metadata" : {
"AWS::CloudFormation::Interface" : {
"ParameterGroups" : {
"Label" : { "default" : "Project Name handson" },
"Parameters" : "handson",
"Label" : { "default" : "Network Configuration" },
"Parameters" : [
"VPCCIDR",
"PrivateSubnet1CIDR", "PrivateSubnet2CIDR",
"PublicSubnet1CIDR", "PublicSubnet2CIDR"
]
},
"ParameterLabels" : {
"VPCCIDR" : { "default" : "VPC CIDR" },
"PrivateSubnet1CIDR" : { "default" : "PrivateSubnet1 CIDR"},
"PrivateSubnet2CIDR" : { "default" : "PrivateSubnet2 CIDR"},
"PublicSubnet1CIDR" : { "default" : "PublicSubnet1 CIDR"},
"PublicSubnet1CIDR" : { "default" : "PublicSubnet1 CIDR"}
}
}
},
// Parameters(オプション)
// 実行時に (スタックを作成または更新するとき)、テンプレートに渡すことができる値を指定します。
↓
"Parameters" : {
"handson" : {
"Type" : "String",
"Default" : "handson"
},
"VPCCIDR" : {
"Type" : "String",
"Default" : "10.0.0.0/24"
},
"PrivateSubnet1CIDR" : {
"Type" : "String",
"Default" : "10.0.0.0/26"
},
"PrivateSubnet2CIDR" : {
"Type" : "String",
"Default" : "10.0.0.64/26"
},
"PublicSubnet1CIDR" : {
"Type" : "String",
"Default" : "10.0.0.128/26"
},
"PublicSubnet2CIDR" : {
"Type" : "String",
"Default" : "10.0.0.192/26"
}
},
// Resources(必須)
// 実際に構築するリソースとそのプロパティを指定します。
↓
"Resources" : {
//VPCを作成
"VPC" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : { "Ref" : "VPCCIDR" },
"EnableDnsHostnames" : "true",
"EnableDnsSupport" : "true",
"InstanceTenancy" : "default",
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-vpc" }}
]
}
},
// プライベートサブネット1を作成
"PrivateSubnet1" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"AvailabilityZone" : "ap-northeast-3a",
"CidrBlock" : { "Ref" : "PrivateSubnet1CIDR" },
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{"Key" : "name", "Value" : "my-private-subnet1"}
]
}
},
// プライベートサブネット2を作成
"PrivateSubnet2" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"AvailabilityZone" : "ap-northeast-3b",
"CidrBlock" : { "Ref" : "PrivateSubnet2CIDR" },
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{"Key" : "name", "Value" : "my-private-subnet2"}
]
}
},
// パブリックサブネット1を作成
"PublicSubnet1" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"AvailabilityZone" : "ap-northeast-3a",
"CidrBlock" : { "Ref" : "PublicSubnet1CIDR" },
"VpcId" : { "Ref" : "VPC" },
"MapPublicIpOnLaunch" : "true",
"Tags" : [
{"Key" : "name", "Value" : "my-public-subnet1"}
]
}
},
// パブリックサブネット2を作成
"PublicSubnet2" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"AvailabilityZone" : "ap-northeast-3b",
"CidrBlock" : { "Ref" : "PublicSubnet2CIDR" },
"VpcId" : { "Ref" : "VPC" },
"MapPublicIpOnLaunch" : "true",
"Tags" : [
{"Key" : "name", "Value" : "my-public-subnet2"}
]
}
},
// インターネットゲートウェイを作成
"InternetGateway" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-igw" }}
]
}
},
// インターネットゲートウェイをVPCにアタッチ
"AttachGateway" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"InternetGatewayId" : { "Ref" : "InternetGateway" }
}
},
// NATゲートウェイ1を作成
"NATGateway1" : {
"Type" : "AWS::EC2::NatGateway",
"Properties" : {
"AllocationId" : { "Fn::GetAtt" : ["EIP1", "AllocationId"]},
"SubnetId" : { "Ref" : "PublicSubnet1"},
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-ngw1" }}
]
}
},
// NATゲートウェイ1にElastic IPを付与
"EIP1" : {
"DependsOn" : "AttachGateway",
"Type" : "AWS::EC2::EIP",
"Properties" : {
"Domain" : "vpc"
}
},
// NATゲートウェイ2を作成
"NATGateway2" : {
"Type" : "AWS::EC2::NatGateway",
"Properties" : {
"AllocationId" : { "Fn::GetAtt" : ["EIP2", "AllocationId"]},
"SubnetId" : { "Ref" : "PublicSubnet2"},
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-ngw2" }}
]
}
},
// NATゲートウェイ2にElastic IPを付与
"EIP2" : {
"DependsOn" : "AttachGateway",
"Type" : "AWS::EC2::EIP",
"Properties" : {
"Domain" : "vpc"
}
},
// パブリックサブネットのルートテーブルを作成
"PublicRouteTable" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-pub-rt" }}
]
}
},
// プライベートサブネット1のルートテーブルを作成
"PrivateRouteTable1" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-pri-rt1" }}
]
}
},
// プライベートサブネット2のルートテーブルを作成
"PrivateRouteTable2" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{"Key" : "name", "Value" : { "Fn::Sub" : "${handson}-pri-rt2" }}
]
}
},
// パブリックサブネットのルートテーブルの送信先に「0.0.0.0/0」、ターゲットに「インターネットゲートウェイ」を指定
"Route" : {
"Type" : "AWS::EC2::Route",
"Properties" : {
"RouteTableId" : { "Ref" : "PublicRouteTable" },
"DestinationCidrBlock" : "0.0.0.0/0",
"GatewayId" : { "Ref" : "InternetGateway" }
}
},
// プライベートサブネット1のルートテーブルの送信先に「0.0.0.0/0」、ターゲットに「NATゲートウェイ1」を指定
"NATRoute1" : {
"Type" : "AWS::EC2::Route",
"Properties" : {
"RouteTableId" : { "Ref" : "PrivateRouteTable1" },
"DestinationCidrBlock" : "0.0.0.0/0",
"NatGatewayId" : { "Ref" : "NATGateway1" }
}
},
// プライベートサブネット2のルートテーブルの送信先に「0.0.0.0/0」、ターゲットに「NATゲートウェイ2」を指定
"NATRoute2" : {
"Type" : "AWS::EC2::Route",
"Properties" : {
"RouteTableId" : { "Ref" : "PrivateRouteTable2" },
"DestinationCidrBlock" : "0.0.0.0/0",
"NatGatewayId" : { "Ref" : "NATGateway2" }
}
},
// パブリックサブネット1にルートテーブルを関連付け
"PublicSubnet1RouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PublicSubnet1" },
"RouteTableId" : { "Ref" : "PublicRouteTable" }
}
},
// パブリックサブネット2にルートテーブルを関連付け
"PublicSubnet2RouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PublicSubnet2" },
"RouteTableId" : { "Ref" : "PublicRouteTable" }
}
},
// プライベートサブネット1にルートテーブルを関連付け
"PrivateSubnet1RouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PrivateSubnet1" },
"RouteTableId" : { "Ref" : "PrivateRouteTable1" }
}
},
// プライベートサブネット2にルートテーブルを関連付け
"PrivateSubnet2RouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PrivateSubnet2" },
"RouteTableId" : { "Ref" : "PrivateRouteTable2" }
}
}
},
// Outputs(オプション)
// スタックのプロパティを確認すると返される値を指定します。
↓
"Outputs" : {
"VPC" : {
"Value" : { "Ref" : "VPC" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-vpc" }
}
},
"PrivateSubnet1" : {
"Value" : { "Ref" : "PrivateSubnet1" },
"Export" : {
"Name" : "my-private-subnet1"
}
},
"PrivateSubnet2" : {
"Value" : { "Ref" : "PrivateSubnet2" },
"Export" : {
"Name" : "my-private-subnet2"
}
},
"PublicSubnet1" : {
"Value" : { "Ref" : "PublicSubnet1" },
"Export" : {
"Name" : "my-public-subnet1"
}
},
"PublicSubnet2" : {
"Value" : { "Ref" : "PublicSubnet2" },
"Export" : {
"Name" : "my-public-subnet2"
}
},
"InternetGateway" : {
"Value" : { "Ref" : "InternetGateway" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-igw" }
}
},
"NATGateway1" : {
"Value" : { "Ref" : "NATGateway1" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-ngw1" }
}
},
"NATGateway2" : {
"Value" : { "Ref" : "NATGateway2" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-ngw2" }
}
},
"PublicRouteTable" : {
"Value" : { "Ref" : "PublicRouteTable" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-pub-rt" }
}
},
"PrivateRouteTable1" : {
"Value" : { "Ref" : "PrivateRouteTable1" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-pri-rt1" }
}
},
"PrivateRouteTable2" : {
"Value" : { "Ref" : "PrivateRouteTable2" },
"Export" : {
"Name" : { "Fn::Sub" : "${handson}-pri-rt2" }
}
}
}
}
【CloudFormationでスタックを作成する】
- IAMユーザでログインします。
- 管理コンソールの検索バーで「CloudFormation」と入力して選択します。
- CloudFormationのダッシュボードを開きます。
- 今回は大阪リージョンを選択します。
- 画面左の「スタック」をクリックし、画面右上の[スタックの作成]をクリックします。
- 「スタックの作成」画面の「テンプレートの準備」で「テンプレートの準備完了」を選択します。
- 「テンプレートの指定」で「テンプレートファイルのアップロード」を選択し、作成したjsonをアップロードします。
- アップロードしたら[次へ]をクリックします。
- 「スタックの詳細を指定」画面の「スタックの名前」を任意で指定し、[次へ]をクリックします。
- 「スタックオプションの設定」画面では、今回何も指定せずに[次へ]をクリックします。
- 「レビュー」画面で内容を確認し、問題がなければ[スタックの作成]をクリックします。
【作成したリソースを確認する】
スタックの作成を開始すると、以下のように「ステータス」が「CREATE_IN_PROGRESS」となっていますが、作成が完了すると「CREATE _COMPLETE」になります。
- 「出力」タブを選択すると、Outputsで指定した項目が出力されていることが確認できます。
これで、CloudFormationを利用してネットワーク環境を構築することができました。
【さいごに】
今回は、AWS CloudFormationを利用してネットワーク環境を構築しました。
AWS初学者の方にはハードルの高い「AWS CloudFormation」ですが、自分で書いたコードで環境構築が上手くいったときの嬉しさを是非一度味わってみるのも良いと思います。
↓今回使用したjsonファイルのダウンロードはこちらから
コメント