Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
433 lines (389 sloc) 12 KB
from troposphere import (
AWS_REGION,
AWS_STACK_ID,
AWS_STACK_NAME,
autoscaling,
Base64,
cloudformation,
FindInMap,
GetAtt,
iam,
Join,
Output,
Parameter,
Ref,
)
from troposphere.ec2 import (
SecurityGroup,
SecurityGroupRule,
)
from troposphere.ecs import (
Cluster,
)
from troposphere.elasticloadbalancingv2 import (
Action,
Certificate,
Listener,
LoadBalancer,
Matcher,
TargetGroup,
TargetGroupAttribute,
)
from awacs import ecr
from .template import template
from .vpc import (
vpc,
loadbalancer_a_subnet,
loadbalancer_a_subnet_cidr,
loadbalancer_b_subnet,
loadbalancer_b_subnet_cidr,
container_a_subnet,
container_b_subnet,
)
from .assets import (
assets_bucket,
)
from .certificates import application as application_certificate
container_instance_type = Ref(template.add_parameter(Parameter(
"ContainerInstanceType",
Description="The container instance type",
Type="String",
Default="t2.micro",
AllowedValues=["t2.micro", "t2.small", "t2.medium"]
)))
web_worker_port = Ref(template.add_parameter(Parameter(
"WebWorkerPort",
Description="Web worker container exposed port",
Type="Number",
Default="8000",
)))
max_container_instances = Ref(template.add_parameter(Parameter(
"MaxScale",
Description="Maximum container instances count",
Type="Number",
Default="3",
)))
desired_container_instances = Ref(template.add_parameter(Parameter(
"DesiredScale",
Description="Desired container instances count",
Type="Number",
Default="3",
)))
template.add_mapping("ECSRegionMap", {
"us-east-1": {"AMI": "ami-eca289fb"},
"us-east-2": {"AMI": "ami-446f3521"},
"us-west-1": {"AMI": "ami-9fadf8ff"},
"us-west-2": {"AMI": "ami-7abc111a"},
"eu-west-1": {"AMI": "ami-a1491ad2"},
"eu-central-1": {"AMI": "ami-54f5303b"},
"ap-northeast-1": {"AMI": "ami-9cd57ffd"},
"ap-southeast-1": {"AMI": "ami-a900a3ca"},
"ap-southeast-2": {"AMI": "ami-5781be34"},
})
# Target group
application_target_group = TargetGroup(
'ApplicationTargetGroup',
template=template,
VpcId=Ref(vpc),
Matcher=Matcher(
HttpCode='200-299',
),
Port=80,
Protocol='HTTP',
HealthCheckIntervalSeconds=15,
HealthCheckPath='/health-check',
HealthCheckProtocol='HTTP',
HealthCheckTimeoutSeconds=5,
HealthyThresholdCount=2,
UnhealthyThresholdCount=8,
TargetGroupAttributes=[
TargetGroupAttribute(
Key='stickiness.enabled',
Value='true',
)
],
)
# Web load balancer
load_balancer_security_group = SecurityGroup(
"LoadBalancerSecurityGroup",
template=template,
GroupDescription="Web load balancer security group.",
VpcId=Ref(vpc),
SecurityGroupIngress=[
SecurityGroupRule(
IpProtocol="tcp",
FromPort="443",
ToPort="443",
CidrIp='0.0.0.0/0',
),
],
)
application_load_balancer = LoadBalancer(
'ApplicationLoadBalancer',
template=template,
Subnets=[
Ref(loadbalancer_a_subnet),
Ref(loadbalancer_b_subnet),
],
SecurityGroups=[Ref(load_balancer_security_group)],
)
template.add_output(Output(
"LoadBalancerDNSName",
Description="Loadbalancer DNS",
Value=GetAtt(application_load_balancer, "DNSName")
))
application_listener = Listener(
'ApplicationListener',
template=template,
Certificates=[Certificate(
CertificateArn=application_certificate,
)],
LoadBalancerArn=Ref(application_load_balancer),
Protocol='HTTPS',
Port=443,
DefaultActions=[Action(
TargetGroupArn=Ref(application_target_group),
Type='forward',
)]
)
# ECS cluster
cluster = Cluster(
"Cluster",
template=template,
)
# ECS container role
container_instance_role = iam.Role(
"ContainerInstanceRole",
template=template,
AssumeRolePolicyDocument=dict(Statement=[dict(
Effect="Allow",
Principal=dict(Service=["ec2.amazonaws.com"]),
Action=["sts:AssumeRole"],
)]),
Path="/",
Policies=[
iam.Policy(
PolicyName="AssetsManagementPolicy",
PolicyDocument=dict(
Statement=[dict(
Effect="Allow",
Action=[
"s3:ListBucket",
],
Resource=Join("", [
"arn:aws:s3:::",
Ref(assets_bucket),
]),
), dict(
Effect="Allow",
Action=[
"s3:*",
],
Resource=Join("", [
"arn:aws:s3:::",
Ref(assets_bucket),
"/*",
]),
)],
),
),
iam.Policy(
PolicyName="ECSManagementPolicy",
PolicyDocument=dict(
Statement=[dict(
Effect="Allow",
Action=[
"ecs:*",
"elasticloadbalancing:*",
],
Resource="*",
)],
),
),
iam.Policy(
PolicyName='ECRManagementPolicy',
PolicyDocument=dict(
Statement=[dict(
Effect='Allow',
Action=[
ecr.GetAuthorizationToken,
ecr.GetDownloadUrlForLayer,
ecr.BatchGetImage,
ecr.BatchCheckLayerAvailability,
],
Resource="*",
)],
),
),
iam.Policy(
PolicyName="LoggingPolicy",
PolicyDocument=dict(
Statement=[dict(
Effect="Allow",
Action=[
"logs:Create*",
"logs:PutLogEvents",
],
Resource="arn:aws:logs:*:*:*",
)],
),
),
]
)
# ECS container instance profile
container_instance_profile = iam.InstanceProfile(
"ContainerInstanceProfile",
template=template,
Path="/",
Roles=[Ref(container_instance_role)],
)
container_security_group = SecurityGroup(
'ContainerSecurityGroup',
template=template,
GroupDescription="Container security group.",
VpcId=Ref(vpc),
SecurityGroupIngress=[
# HTTP from web public subnets
SecurityGroupRule(
IpProtocol="tcp",
FromPort=web_worker_port,
ToPort=web_worker_port,
CidrIp=loadbalancer_a_subnet_cidr,
),
SecurityGroupRule(
IpProtocol="tcp",
FromPort=web_worker_port,
ToPort=web_worker_port,
CidrIp=loadbalancer_b_subnet_cidr,
),
],
)
container_instance_configuration_name = "ContainerLaunchConfiguration"
autoscaling_group_name = "AutoScalingGroup"
container_instance_configuration = autoscaling.LaunchConfiguration(
container_instance_configuration_name,
template=template,
Metadata=autoscaling.Metadata(
cloudformation.Init(dict(
config=cloudformation.InitConfig(
commands=dict(
register_cluster=dict(command=Join("", [
"#!/bin/bash\n",
# Register the cluster
"echo ECS_CLUSTER=",
Ref(cluster),
" >> /etc/ecs/ecs.config\n",
# Enable CloudWatch docker logging
'echo \'ECS_AVAILABLE_LOGGING_DRIVERS=',
'["json-file","awslogs"]\'',
" >> /etc/ecs/ecs.config\n",
]))
),
files=cloudformation.InitFiles({
"/etc/cfn/cfn-hup.conf": cloudformation.InitFile(
content=Join("", [
"[main]\n",
"stack=",
Ref(AWS_STACK_ID),
"\n",
"region=",
Ref(AWS_REGION),
"\n",
]),
mode="000400",
owner="root",
group="root",
),
"/etc/cfn/hooks.d/cfn-auto-reloader.conf":
cloudformation.InitFile(
content=Join("", [
"[cfn-auto-reloader-hook]\n",
"triggers=post.update\n",
"path=Resources.%s."
% container_instance_configuration_name,
"Metadata.AWS::CloudFormation::Init\n",
"action=/opt/aws/bin/cfn-init -v ",
" --stack ",
Ref(AWS_STACK_NAME),
" --resource %s"
% container_instance_configuration_name,
" --region ",
Ref("AWS::Region"),
"\n",
"runas=root\n",
])
)
}),
services=dict(
sysvinit=cloudformation.InitServices({
'cfn-hup': cloudformation.InitService(
enabled=True,
ensureRunning=True,
files=[
"/etc/cfn/cfn-hup.conf",
"/etc/cfn/hooks.d/cfn-auto-reloader.conf",
]
),
})
)
)
))
),
SecurityGroups=[Ref(container_security_group)],
InstanceType=container_instance_type,
ImageId=FindInMap("ECSRegionMap", Ref(AWS_REGION), "AMI"),
IamInstanceProfile=Ref(container_instance_profile),
UserData=Base64(Join('', [
"#!/bin/bash -xe\n",
"yum install -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ", Ref(AWS_STACK_NAME),
" --resource %s " % container_instance_configuration_name,
" --region ", Ref(AWS_REGION), "\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", Ref(AWS_STACK_NAME),
" --resource %s " % container_instance_configuration_name,
" --region ", Ref(AWS_REGION), "\n",
])),
)
autoscaling_group = autoscaling.AutoScalingGroup(
autoscaling_group_name,
template=template,
VPCZoneIdentifier=[Ref(container_a_subnet), Ref(container_b_subnet)],
MinSize=desired_container_instances,
MaxSize=max_container_instances,
DesiredCapacity=desired_container_instances,
LaunchConfigurationName=Ref(container_instance_configuration),
HealthCheckType="EC2",
HealthCheckGracePeriod=300,
)
app_service_role = iam.Role(
"AppServiceRole",
template=template,
AssumeRolePolicyDocument=dict(Statement=[dict(
Effect="Allow",
Principal=dict(Service=["ecs.amazonaws.com"]),
Action=["sts:AssumeRole"],
)]),
Path="/",
Policies=[
iam.Policy(
PolicyName="WebServicePolicy",
PolicyDocument=dict(
Statement=[dict(
Effect="Allow",
Action=[
"elasticloadbalancing:Describe*",
"elasticloadbalancing"
":DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing"
":RegisterInstancesWithLoadBalancer",
"ec2:Describe*",
"ec2:AuthorizeSecurityGroupIngress",
],
Resource="*",
)],
),
),
]
)