CloudFormationを最近触り始めた私がAWS CDKを使ってEC2作成まで挑戦します
前提条件
以下インストールされていること
Python3
aws cli
aws cdk
app作成
以下を参考にapp作成していきます
$ mkdir cdk-app
$ cd cdk-app
$ cdk init app --language python
$ source .venv/bin/activate
$ python -m pip install -r requirements.txt
$ cdk bootstrap
成功するとこんな感じにファイルができます
$ ls -a
. .venv cdk_app tests
.. README.md requirements-dev.txt
.git app.py requirements.txt
.gitignore cdk.json source.bat
実装
どこに処理を書いていけばいいんじゃ.....?
生成されたファイルの中に「cdk_app_stack.py」というファイルがありました
どうやらここに処理を書いていくようです
$ cd cdk_app/
$ ls -a
. .. __init__.py cdk_app_stack.py
$ cat cdk_app_stack.py
from aws_cdk import (
# Duration,
Stack,
# aws_sqs as sqs,
)
from constructs import Construct
class CdkAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# The code that defines your stack goes here
# example resource
# queue = sqs.Queue(
# self, "CdkAppQueue",
# visibility_timeout=Duration.seconds(300),
# )
VPC作成
さっそくVPCとサブネットの部分を実装していきます
from aws_cdk import (
# Duration,
aws_ec2 as ec2,
Stack,
)
from constructs import Construct
class CdkAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create VPC
vpc = ec2.Vpc(
self,
id="vpc",
cidr="10.0.0.0/16",
nat_gateways=0, # NatGatewayを作成しない指定
# Create Private Subnet
subnet_configuration=[
ec2.SubnetConfiguration(
name="subnet",
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24
)
]
)
以下を実行することで実装した内容が正しく動くのかチェックできるのと、作成するリソースの内容が見れます
$ cdk diff
作成されるリソース
〜〜〜省略〜〜〜
Resources
[+] AWS::EC2::VPC vpc vpcA2121C38
[+] AWS::EC2::Subnet vpc/subnetSubnet1/Subnet vpcsubnetSubnet1SubnetED4FAF75
[+] AWS::EC2::RouteTable vpc/subnetSubnet1/RouteTable vpcsubnetSubnet1RouteTable540CA842
[+] AWS::EC2::SubnetRouteTableAssociation vpc/subnetSubnet1/RouteTableAssociation vpcsubnetSubnet1RouteTableAssociation8AB5D956
[+] AWS::EC2::Route vpc/subnetSubnet1/DefaultRoute vpcsubnetSubnet1DefaultRoute693F9670
[+] AWS::EC2::Subnet vpc/subnetSubnet2/Subnet vpcsubnetSubnet2Subnet1FDD234B
[+] AWS::EC2::RouteTable vpc/subnetSubnet2/RouteTable vpcsubnetSubnet2RouteTable76DD52F4
[+] AWS::EC2::SubnetRouteTableAssociation vpc/subnetSubnet2/RouteTableAssociation vpcsubnetSubnet2RouteTableAssociationE50AAA12
[+] AWS::EC2::Route vpc/subnetSubnet2/DefaultRoute vpcsubnetSubnet2DefaultRouteD284164C
[+] AWS::EC2::InternetGateway vpc/IGW vpcIGWE57CBDCA
[+] AWS::EC2::VPCGatewayAttachment vpc/VPCGW vpcVPCGW7984C166
〜〜〜省略〜〜〜
ではデプロイしてみましょう
$ cdk deploy
VPCとサブネットが作成されてました!
ルートテーブルやインターネットゲートウェイも作られてました!
ここはCloudFormationだと書かないと作られないので楽ですね
(自分で作ることもできそうです)
EC2作成
セキュリティグループもあわせて実装します
from aws_cdk import (
# Duration,
aws_ec2 as ec2,
Stack,
)
from constructs import Construct
class CdkAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Create VPC
vpc = ec2.Vpc(
self,
id="vpc",
cidr="10.0.0.0/16",
nat_gateways=0, # NatGatewayを作成しない指定
# Create Private Subnet
subnet_configuration=[
ec2.SubnetConfiguration(
name="subnet",
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24
)
]
)
# Create SecurityGroup
security_group = ec2.SecurityGroup(
self,
id="ec2-sg",
vpc=vpc,
allow_all_outbound=True,
security_group_name="ec2-sg"
)
# Add Ingress Rule
security_group.add_ingress_rule(
peer=ec2.Peer.ipv4("**********/32"),
connection=ec2.Port.tcp(22),
description="allow ssh access"
)
# Create EC2
ec2_instance = ec2.Instance(
self,
id="ec2-instance",
instance_type=ec2.InstanceType.of(
ec2.InstanceClass.BURSTABLE2,
ec2.InstanceSize.MICRO
),
machine_image=ec2.AmazonLinuxImage(),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC
),
instance_name="ec2-instance",
security_group=security_group
)
できたので再度diff...
$ cdk diff
ちゃんと差分のみ表示してくれますね!
とても見やすいです!
IAM Statement Changes
┌───┬──────────────────────────────┬────────┬────────────────┬──────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────────────────────────┼────────┼────────────────┼──────────────────────────────┼───────────┤
│ + │ ${ec2-instance/InstanceRole. │ Allow │ sts:AssumeRole │ Service:ec2.${AWS::URLSuffix │ │
│ │ Arn} │ │ │ } │ │
└───┴──────────────────────────────┴────────┴────────────────┴──────────────────────────────┴───────────┘
Security Group Changes
┌───┬───────────────────┬─────┬────────────┬────────────────────┐
│ │ Group │ Dir │ Protocol │ Peer │
├───┼───────────────────┼─────┼────────────┼────────────────────┤
│ + │ ${ec2-sg.GroupId} │ In │ TCP 22 │ **********/32 │
│ + │ ${ec2-sg.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴───────────────────┴─────┴────────────┴────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Parameters
[+] Parameter SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn-ami-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter: {"Type":"AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>","Default":"/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2"}
Resources
[+] AWS::EC2::SecurityGroup ec2-sg ec2sg81ADD929
[+] AWS::IAM::Role ec2-instance/InstanceRole ec2instanceInstanceRoleCA97C688
[+] AWS::IAM::InstanceProfile ec2-instance/InstanceProfile ec2instanceInstanceProfile9BCE9015
[+] AWS::EC2::Instance ec2-instance ec2instance42082E81
そしてデプロイ
$ cdk deploy
EC2作成されてました!
メソッド化
せっかくyamlでなくPythonで書いているので、プログラムみたいにしたい!
ということでメソッドを作ってみます
def create_ec2(self, id, vpc, security_group):
return ec2.Instance(
self,
id=id,
instance_type=ec2.InstanceType.of(
ec2.InstanceClass.BURSTABLE2,
ec2.InstanceSize.MICRO
),
machine_image=ec2.AmazonLinuxImage(),
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC
),
instance_name=id,
security_group=security_group
)
単純ですがEC2を作成するメソッドを作成しました
idを変えて呼び出す
このidの部分がCloudFormationでいうResourcesIdの部分なので同じ値は指定できません
# EC2インスタンスを作成
ec2_instance = self.create_ec2("ec2-instance", vpc, security_group)
ec2_instance2 = self.create_ec2("ec2-instance2", vpc, security_group)
これでデプロイしてみると.....
2つ作成されてました!
素敵ですね!!
スタック削除
一通り試せたので次はスタックの削除をしてみます
削除するときはdestroyコマンドです
$ cdk destroy
消す前にスタック名の確認をしてくれるので精神的に安心ですw
Are you sure you want to delete: CdkAppStack (y/n)?
最初に作成したVPCまで削除されてました
感想
CDKで実行するとターミナル上で見れる情報が多く、コマンド実行してからの不安が軽減された感じがしました
あとやっぱりメソッド化できるのがいいですね!
CloudFormationだとどうしても冗長化したソースになってしまい読みづらくなってしまうので、、、
今後構築する案件ではCDK使って行きたいなととても感じました
以上
Tips
公式サンプル
app作成