Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add VPC, EC2 Python Example #204

Merged
merged 6 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/DO_NOT_AUTOTEST
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

17 changes: 17 additions & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Create EC2 in an existing VPC with AWS CDK Python

This is a project to create a new EC2 in an existing VPC on AWS with the AWS Cloud Development Kit.

This project also demonstrates:
* Using customized user data of EC2
* Customize multiple EBS volume
* Specify AMI id
* Security groups allow SSH access from internet

## Useful commands

* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
13 changes: 13 additions & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python3

from aws_cdk import core

from cdk_vpc_ec2.cdk_vpc_ec2_stack import CdkVpcEc2Stack

# Define your account id to make import vpc work
env_cn = core.Environment(account="YOUR_ACCOUNT_ID_WITHOUT_HYPHEN", region="cn-northwest-1")

app = core.App()
CdkVpcEc2Stack(app, "cdk-vpc-ec2", env=env_cn)

app.synth()
3 changes: 3 additions & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "python3 app.py"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from aws_cdk import core
import aws_cdk.aws_ec2 as ec2

vpc_id = "MY-VPC-ID" # Import an Exist VPC
ec2_type = "t2.micro"
key_name = "id_rsa"
linux_ami = ec2.GenericLinuxImage({
"cn-northwest-1": "AMI-ID-IN-cn-northwest-1-REGION", # Refer to an Exist AMI
"eu-west-1": "AMI-ID-IN-eu-west-1-REGION"
})
with open("./user_data/user_data.sh") as f:
user_data = f.read()


class CdkVpcEc2Stack(core.Stack):

def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)

# The code that defines your stack goes here
vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=vpc_id)

host = ec2.Instance(self, "myEC2",
instance_type=ec2.InstanceType(
instance_type_identifier=ec2_type),
instance_name="mySingleHost",
machine_image=linux_ami,
vpc=vpc,
key_name=key_name,
vpc_subnets=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC),
user_data=ec2.UserData.custom(user_data)
)
# ec2.Instance has no property of BlockDeviceMappings, add via lower layer cdk api:
host.instance.add_property_override("BlockDeviceMappings", [{
"DeviceName": "/dev/xvda",
"Ebs": {
"VolumeSize": "10",
"VolumeType": "io1",
"Iops": "150",
"DeleteOnTermination": "true"
}
}, {
"DeviceName": "/dev/sdb",
"Ebs": {"VolumeSize": "30"}
}
]) # by default VolumeType is gp2, VolumeSize 8GB
host.connections.allow_from_any_ipv4(
ec2.Port.tcp(22), "Allow ssh from internet")
host.connections.allow_from_any_ipv4(
ec2.Port.tcp(80), "Allow ssh from internet")

core.CfnOutput(self, "Output",
value=host.instance_public_ip)
1 change: 1 addition & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .
46 changes: 46 additions & 0 deletions python/existing-vpc-new-ec2-ebs-userdata/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import setuptools


with open("README.md") as fp:
long_description = fp.read()


setuptools.setup(
name="Import_VPC_Create_EC2",
version="1.0.0",

description="Import VPC and Create EC2 on it with two EBS and EC2 UserData",
long_description=long_description,
long_description_content_type="text/markdown",

author="Huang, Zhuobin (James)",

package_dir={"": "cdk_vpc_ec2"},
packages=setuptools.find_packages(where="cdk_vpc_ec2"),

install_requires=[
"aws-cdk.core",
"aws-cdk.aws-ec2"
],

python_requires=">=3.6",

classifiers=[
"Development Status :: 4 - Beta",

"Intended Audience :: Developers",

"License :: OSI Approved :: Apache Software License",

"Programming Language :: JavaScript",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",

"Topic :: Software Development :: Code Generators",
"Topic :: Utilities",

"Typing :: Typed",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
sudo yum update -y
sudo yum -y install httpd php
sudo chkconfig httpd on
sudo service httpd start
24 changes: 24 additions & 0 deletions python/new-vpc-alb-asg-mysql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Create VPC, EC2 ASG and RDS with AWS CDK Python

This is a project to create a new VPC, EC2 autoscaling group and RDS on AWS with the AWS Cloud Development Kit.

This project also demonstrates:
* Create VPC in 3 tier layers of subnets: PUBLIC, PRIVATE and ISOLATED, you can specify the number of AZ and the CIDR.
* Create Bastion instance, NAT Gateway and S3 endpoint
* Create ALB, EC2 Autoscaling group with scaling policy and customize EBS volume
* Creat RDS MySQL M-AZs Database or Aurora
* Create security group and allow access from the other security group: Internet -> ALB -> EC2ASG -> RDS
* Using customized user data of EC2 and specify generation AMI property and do not need to specify the AMI id in every region

## Architeture
![Architecture](./img_demo_cdk_vpc.png)

This project create the new VPC part of the architeture. For the existing VPC part, please refer to the project in aws-cdk-examples/existing-vpc-new-ec2-ebs-userdata

## Useful commands

* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
18 changes: 18 additions & 0 deletions python/new-vpc-alb-asg-mysql/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python3

from aws_cdk import core

from cdk_vpc_ec2.cdk_vpc_stack import CdkVpcStack
from cdk_vpc_ec2.cdk_ec2_stack import CdkEc2Stack
from cdk_vpc_ec2.cdk_rds_stack import CdkRdsStack

app = core.App()

vpc_stack = CdkVpcStack(app, "cdk-vpc")
ec2_stack = CdkEc2Stack(app, "cdk-ec2",
vpc=vpc_stack.vpc)
rds_stack = CdkRdsStack(app, "cdk-rds",
vpc=vpc_stack.vpc,
asg_security_groups=ec2_stack.asg.connections.security_groups)

app.synth()
3 changes: 3 additions & 0 deletions python/new-vpc-alb-asg-mysql/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "python3 app.py"
}
82 changes: 82 additions & 0 deletions python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_ec2_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from aws_cdk import core
import aws_cdk.aws_ec2 as ec2
import aws_cdk.aws_elasticloadbalancingv2 as elb
import aws_cdk.aws_autoscaling as autoscaling

ec2_type = "t2.micro"
key_name = "id_rsa" # Setup key_name for EC2 instance login
linux_ami = ec2.AmazonLinuxImage(generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX,
edition=ec2.AmazonLinuxEdition.STANDARD,
virtualization=ec2.AmazonLinuxVirt.HVM,
storage=ec2.AmazonLinuxStorage.GENERAL_PURPOSE
) # Indicate your AMI, no need a specific id in the region
with open("./user_data/user_data.sh") as f:
user_data = f.read()


class CdkEc2Stack(core.Stack):

def __init__(self, scope: core.Construct, id: str, vpc, **kwargs) -> None:
super().__init__(scope, id, **kwargs)

# Create Bastion
bastion = ec2.BastionHostLinux(self, "myBastion",
vpc=vpc,
subnet_selection=ec2.SubnetSelection(
subnet_type=ec2.SubnetType.PUBLIC),
instance_name="myBastionHostLinux",
instance_type=ec2.InstanceType(instance_type_identifier="t2.micro"))

# Setup key_name for EC2 instance login if you don't use Session Manager
# bastion.instance.instance.add_property_override("KeyName", key_name)

bastion.connections.allow_from_any_ipv4(
ec2.Port.tcp(22), "Internet access SSH")

# Create ALB
alb = elb.ApplicationLoadBalancer(self, "myALB",
vpc=vpc,
internet_facing=True,
load_balancer_name="myALB"
)
alb.connections.allow_from_any_ipv4(
ec2.Port.tcp(80), "Internet access ALB 80")
listener = alb.add_listener("my80",
port=80,
open=True)

# Create Autoscaling Group with fixed 2*EC2 hosts
self.asg = autoscaling.AutoScalingGroup(self, "myASG",
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE),
instance_type=ec2.InstanceType(instance_type_identifier=ec2_type),
machine_image=linux_ami,
key_name=key_name,
user_data=ec2.UserData.custom(user_data),
desired_capacity=2,
min_capacity=2,
max_capacity=2,
# block_devices=[
# autoscaling.BlockDevice(
# device_name="/dev/xvda",
# volume=autoscaling.BlockDeviceVolume.ebs(
# volume_type=autoscaling.EbsDeviceVolumeType.GP2,
# volume_size=12,
# delete_on_termination=True
# )),
# autoscaling.BlockDevice(
# device_name="/dev/sdb",
# volume=autoscaling.BlockDeviceVolume.ebs(
# volume_size=20)
# # 20GB, with default volume_type gp2
# )
# ]
)

self.asg.connections.allow_from(alb, ec2.Port.tcp(80), "ALB access 80 port of EC2 in Autoscaling Group")
listener.add_targets("addTargetGroup",
port=80,
targets=[self.asg])

core.CfnOutput(self, "Output",
value=alb.load_balancer_dns_name)
53 changes: 53 additions & 0 deletions python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_rds_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from aws_cdk import core
import aws_cdk.aws_ec2 as ec2
import aws_cdk.aws_rds as rds


class CdkRdsStack(core.Stack):

def __init__(self, scope: core.Construct, id: str, vpc, asg_security_groups, **kwargs) -> None:
super().__init__(scope, id, **kwargs)

# Ceate Aurora Cluster with 2 instances with CDK High Level API
# Secrets Manager auto generate and keep the password, don't put password in cdk code directly
# db_Aurora_cluster = rds.DatabaseCluster(self, "MyAurora",
# default_database_name="MyAurora",
# engine=rds.DatabaseClusterEngine.AURORA_MYSQL,
# engine_version="5.7.12",
# master_user=rds.Login(username="admin"),
# instance_props=rds.InstanceProps(
# vpc=vpc,
# vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.ISOLATED),
# instance_type=ec2.InstanceType(instance_type_identifier="t2.small")
# ),
# instances=2,
# parameter_group=rds.ClusterParameterGroup.from_parameter_group_name(
# self, "para-group-aurora",
# parameter_group_name="default.aurora-mysql5.7"
# ),
# )
# for asg_sg in asg_security_groups:
# db_Aurora_cluster.connections.allow_default_port_from(asg_sg, "EC2 Autoscaling Group access Aurora")

# Alternatively, create MySQL RDS with CDK High Level API
db_mysql_easy = rds.DatabaseInstance(self, "MySQL_DB_easy",
engine=rds.DatabaseInstanceEngine.MYSQL,
engine_version="5.7.22",
instance_class=ec2.InstanceType.of(
ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
master_username="admin",
vpc=vpc,
multi_az=True,
allocated_storage=100,
storage_type=rds.StorageType.GP2,
cloudwatch_logs_exports=["audit", "error", "general", "slowquery"],
deletion_protection=False,
delete_automated_backups=False,
backup_retention=core.Duration.days(7),
parameter_group=rds.ParameterGroup.from_parameter_group_name(
self, "para-group-mysql",
parameter_group_name="default.mysql5.7"
)
)
for asg_sg in asg_security_groups:
db_mysql_easy.connections.allow_default_port_from(asg_sg, "EC2 Autoscaling Group access MySQL")
34 changes: 34 additions & 0 deletions python/new-vpc-alb-asg-mysql/cdk_vpc_ec2/cdk_vpc_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from aws_cdk import core
import aws_cdk.aws_ec2 as ec2


class CdkVpcStack(core.Stack):

def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)

# The code that defines your stack goes here

self.vpc = ec2.Vpc(self, "VPC",
max_azs=2,
cidr="10.10.0.0/16",
# configuration will create 3 groups in 2 AZs = 6 subnets.
subnet_configuration=[ec2.SubnetConfiguration(
subnet_type=ec2.SubnetType.PUBLIC,
name="Public",
cidr_mask=24
), ec2.SubnetConfiguration(
subnet_type=ec2.SubnetType.PRIVATE,
name="Private",
cidr_mask=24
), ec2.SubnetConfiguration(
subnet_type=ec2.SubnetType.ISOLATED,
name="DB",
cidr_mask=24
)
],
# nat_gateway_provider=ec2.NatProvider.gateway(),
nat_gateways=2,
)
core.CfnOutput(self, "Output",
value=self.vpc.vpc_id)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/new-vpc-alb-asg-mysql/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .
Loading