def add_ecs_service(self): ''' Add ECS service ''' self.cfn_template.add_resource( Service( title=constants.SERVICE, Cluster=ImportValue(Sub('${Environment}-CLUSTER')), LaunchType='EC2', DesiredCount=int('1'), TaskDefinition=Ref(constants.TASK), Role=Ref(constants.SERVICE_ROLE), DeploymentConfiguration=DeploymentConfiguration( MaximumPercent=int('200'), MinimumHealthyPercent=int('100')), LoadBalancers=[ LoadBalancer(ContainerName='anchore-engine', ContainerPort=int('8228'), TargetGroupArn=ImportValue( Sub('${Environment}-TARGETGROUP-ARN'))) ], PlacementStrategies=[ PlacementStrategy(Type='spread', Field='attribute:ecs.availability-zone'), PlacementStrategy(Type='spread', Field='instanceId') ])) return self.cfn_template
def _add_alb(self, cd, service_name, config, launch_type): sg_name = 'SG' + self.env + service_name svc_alb_sg = SecurityGroup( re.sub(r'\W+', '', sg_name), GroupName=self.env + '-' + service_name, SecurityGroupIngress=self._generate_alb_security_group_ingress( config ), VpcId=Ref(self.vpc), GroupDescription=Sub(service_name + "-alb-sg") ) self.template.add_resource(svc_alb_sg) alb_name = service_name + pascalcase(self.env) if config['http_interface']['internal']: alb_subnets = [ Ref(self.private_subnet1), Ref(self.private_subnet2) ] scheme = "internal" alb_name += 'Internal' alb_name = alb_name[:32] alb = ALBLoadBalancer( 'ALB' + service_name, Subnets=alb_subnets, SecurityGroups=[ self.alb_security_group, Ref(svc_alb_sg) ], Name=alb_name, Tags=[ {'Value': alb_name, 'Key': 'Name'} ], Scheme=scheme ) else: alb_subnets = [ Ref(self.public_subnet1), Ref(self.public_subnet2) ] alb_name = alb_name[:32] alb = ALBLoadBalancer( 'ALB' + service_name, Subnets=alb_subnets, SecurityGroups=[ self.alb_security_group, Ref(svc_alb_sg) ], Name=alb_name, Tags=[ {'Value': alb_name, 'Key': 'Name'} ] ) self.template.add_resource(alb) target_group_name = "TargetGroup" + service_name health_check_path = config['http_interface']['health_check_path'] if 'health_check_path' in config['http_interface'] else "/elb-check" if config['http_interface']['internal']: target_group_name = target_group_name + 'Internal' target_group_config = {} if launch_type == self.LAUNCH_TYPE_FARGATE: target_group_config['TargetType'] = 'ip' service_target_group = TargetGroup( target_group_name, HealthCheckPath=health_check_path, HealthyThresholdCount=2, HealthCheckIntervalSeconds=30, TargetGroupAttributes=[ TargetGroupAttribute( Key='deregistration_delay.timeout_seconds', Value='30' ) ], VpcId=Ref(self.vpc), Protocol="HTTP", Matcher=Matcher(HttpCode="200-399"), Port=int(config['http_interface']['container_port']), HealthCheckTimeoutSeconds=10, UnhealthyThresholdCount=3, **target_group_config ) self.template.add_resource(service_target_group) # Note: This is a ECS Loadbalancer definition. Not an ALB. # Defining this causes the target group to add a target to the correct # port in correct ECS cluster instance for the service container. lb = LoadBalancer( ContainerName=cd.Name, TargetGroupArn=Ref(service_target_group), ContainerPort=int(config['http_interface']['container_port']) ) target_group_action = Action( TargetGroupArn=Ref(target_group_name), Type="forward" ) service_listener = self._add_service_listener( service_name, target_group_action, alb, config['http_interface']['internal'] ) self._add_alb_alarms(service_name, alb) return alb, lb, service_listener, svc_alb_sg
), ContainerDefinition( Name="bigid-ui", Memory="1024", Essential=True, Image=Join("", [ repo_id, "/bigid/bigid-ui", ]), PortMappings=[PortMapping(ContainerPort="8080", HostPort="8080")], ), ], ) app_service = Service( "AppService", template=template, Cluster=Ref(main_cluster), DependsOn=[autoscaling_group_name], DesiredCount=1, LoadBalancers=[ LoadBalancer( ContainerName="bigid-ui", ContainerPort=8080, LoadBalancerName=Ref(load_balancer), ) ], TaskDefinition=Ref(bigid_task_definition), Role=Ref(app_service_role), )
"elasticloadbalancing" ":DeregisterInstancesFromLoadBalancer", "elasticloadbalancing" ":RegisterInstancesWithLoadBalancer", "ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress", ], Resource="*", ) ], ), ), ]) app_service = Service( "AppService", template=template, Cluster=Ref(cluster), Condition=deploy_condition, DependsOn=[autoscaling_group_name], DesiredCount=web_worker_desired_count, LoadBalancers=[ LoadBalancer( ContainerName="WebWorker", ContainerPort=web_worker_port, LoadBalancerName=Ref(load_balancer), ) ], TaskDefinition=Ref(web_task_definition), Role=Ref(app_service_role), )
"ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress", ], Resource="*", ) ], ), ), ]) application_service = Service( "ApplicationService", template=template, Cluster=Ref(cluster), Condition=deploy_condition, DependsOn=[autoscaling_group_name, application_listener.title], DeploymentConfiguration=DeploymentConfiguration( MaximumPercent=135, MinimumHealthyPercent=30, ), DesiredCount=web_worker_desired_count, LoadBalancers=[ LoadBalancer( ContainerName="WebWorker", ContainerPort=web_worker_port, TargetGroupArn=Ref(application_target_group), ) ], TaskDefinition=Ref(web_task_definition), Role=Ref(application_service_role), )
Value=Ref(s3path) ) ] ) ] )) shibboleth_service = t.add_resource(Service( 'ShibbolethService', Cluster=Ref(cluster), DesiredCount=1, TaskDefinition=Ref(shibboleth_task_definition), LoadBalancers=[ LoadBalancer( ContainerName='shibboleth', ContainerPort=8080, TargetGroupArn=Ref(shibboleth_lb_target_arn) ) ] )) redirect_task_definition = t.add_resource(TaskDefinition( 'RedirectTaskDefinition', ContainerDefinitions=[ ContainerDefinition( Name='shibboleth-redirect', Image=Ref(redirect_image), MemoryReservation=256, Essential=True, PortMappings=[PortMapping(ContainerPort=80)], )
] ) ] ) template.add_resource(test_task_definition) service = Service( "service", Cluster="live", DesiredCount=1, LaunchType="EC2", LoadBalancers=[ LoadBalancer( "serviceloadbalancer", ContainerName="helloworld", ContainerPort=80, TargetGroupArn=Ref(test_target_group) ) ], SchedulingStrategy="REPLICA", ServiceName="helloworld", TaskDefinition=Ref(test_task_definition) ) template.add_resource(service) print(template.to_yaml()) # { # "Type" : "AWS::ECS::TaskDefinition", # "Properties" : {
def generate_template(d): # Set template metadata t = Template() t.add_version("2010-09-09") t.set_description(d["cf_template_description"]) aws_account_id = Ref("AWS::AccountId") aws_region = Ref("AWS::Region") # Task definition task_definition = t.add_resource( TaskDefinition( "TaskDefinition", Family=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), RequiresCompatibilities=["FARGATE"], Cpu=d["container_cpu"], Memory=d["container_memory"], NetworkMode="awsvpc", ExecutionRoleArn=ImportValue(d["ecs_stack_name"] + "-ECSClusterRole"), ContainerDefinitions=[ ContainerDefinition( Name=Join("", [ d["env"], "-", d["project_name"], "-", d["service_name"] ]), Image=Join( "", [ aws_account_id, ".dkr.ecr.", aws_region, ".amazonaws.com/", d["env"], d["project_name"], d["service_name"], ":latest" ], ), Essential=True, PortMappings=[ PortMapping( ContainerPort=d["container_port"], HostPort=d["container_port"], ) ], EntryPoint=["sh", "-c"], Command=[d["container_command"]], LogConfiguration=LogConfiguration( LogDriver="awslogs", Options={ "awslogs-region": aws_region, "awslogs-group": Join("", [ d["env"], "-", d["project_name"], "-", d["service_name"] ]), "awslogs-stream-prefix": "ecs", "awslogs-create-group": "true" })) ], Tags=Tags(d["tags"], {"Name": d["project_name"] + "-task-definition"}), )) # ECR ecr = t.add_resource( Repository( "ECR", DependsOn="ListenerRule", RepositoryName=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecr"}), )) # Target group target_group = t.add_resource( elb.TargetGroup( "TargetGroup", Name=Join("", [d["env"], "-", d["service_name"]]), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckPort=d["container_port"], HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", HealthCheckPath=d["tg_health_check_path"], Matcher=elb.Matcher(HttpCode="200-299"), Port=d["container_port"], Protocol="HTTP", TargetType="ip", UnhealthyThresholdCount="3", VpcId=ImportValue(d["network_stack_name"] + "-VPCId"), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecr"}), )) # Listener rule t.add_resource( elb.ListenerRule( "ListenerRule", DependsOn="TargetGroup", ListenerArn=ImportValue(d["ecs_stack_name"] + "-ListenerArnHTTP"), Conditions=[ elb.Condition(Field="path-pattern", Values=[d["application_path_api"]]) ], Actions=[ elb.Action(Type="forward", TargetGroupArn=Ref(target_group)) ], Priority="1", )) # ECS service ecs_service = t.add_resource( Service( "ECSService", ServiceName=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), DependsOn="pipeline", DesiredCount=d["container_desired_tasks_count"], TaskDefinition=Ref(task_definition), LaunchType="FARGATE", NetworkConfiguration=NetworkConfiguration( AwsvpcConfiguration=AwsvpcConfiguration( Subnets=[ ImportValue(d["network_stack_name"] + "-PrivateSubnetId1"), ImportValue(d["network_stack_name"] + "-PrivateSubnetId2"), ], SecurityGroups=[ ImportValue(d["ecs_stack_name"] + "-ECSClusterSG") ], )), LoadBalancers=([ LoadBalancer( ContainerName=Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"] ], ), ContainerPort=d["container_port"], TargetGroupArn=Ref(target_group), ) ]), Cluster=ImportValue(d["ecs_stack_name"] + "-ECSClusterName"), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecs-service"}), )) # App Autoscaling target # App Autoscaling policy # Codebuild project codebuild = t.add_resource( Project( "codebuild", Name=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), DependsOn="ECR", ServiceRole=ImportValue(d["ecs_stack_name"] + "-CodebuildDeveloperRole"), Artifacts=Artifacts( Name="Build", Location=d["artifact_store"], Type="S3", ), Description="Build a docker image and send it to ecr", Source=Source( BuildSpec="buildspec.yml", Type="S3", Location=d["artifact_store"] + "/" + d["artifact_name"], ), Environment=Environment( ComputeType="BUILD_GENERAL1_SMALL", Image="aws/codebuild/standard:4.0", PrivilegedMode=True, Type="LINUX_CONTAINER", EnvironmentVariables=[ EnvironmentVariable( Name="AWS_DEFAULT_REGION", Type="PLAINTEXT", Value=aws_region, ), EnvironmentVariable( Name="SERVICE_NAME", Type="PLAINTEXT", Value=Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"] ], ), ), EnvironmentVariable( Name="IMAGE_URI", Type="PLAINTEXT", Value=Join( "", [ aws_account_id, ".dkr.ecr.", aws_region, ".amazonaws.com/", d["env"], "-", d["project_name"], "-", d["service_name"], ], ), ), ], ), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-codebuild"}), )) # Codepipeline pipeline = t.add_resource( Pipeline( "pipeline", Name=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), RoleArn=ImportValue(d["ecs_stack_name"] + "-CodePipelineRole"), Stages=[ Stages( Name="Source", Actions=[ Actions( Name="Source", ActionTypeId=ActionTypeId( Category="Source", Owner="AWS", Version="1", Provider="S3", ), OutputArtifacts=[ OutputArtifacts(Name="source_artifact") ], Configuration={ "S3Bucket": d["artifact_store"], "S3ObjectKey": d["artifact_name"], }, RunOrder="1", ) ], ), Stages( Name="Build", Actions=[ Actions( Name="Build", InputArtifacts=[ InputArtifacts(Name="source_artifact") ], OutputArtifacts=[ OutputArtifacts(Name="build_artifact") ], ActionTypeId=ActionTypeId( Category="Build", Owner="AWS", Version="1", Provider="CodeBuild", ), Configuration={"ProjectName": Ref(codebuild)}, RunOrder="1", ) ], ), Stages( Name="Deploy", Actions=[ Actions( Name="Deploy", InputArtifacts=[ InputArtifacts(Name="build_artifact") ], ActionTypeId=ActionTypeId( Category="Deploy", Owner="AWS", Version="1", Provider="ECS", ), Configuration={ "ClusterName": ImportValue(d["ecs_stack_name"] + "-ECSClusterName"), "ServiceName": Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"], ], ), "FileName": "definitions.json", }, ) ], ), ], ArtifactStore=ArtifactStore(Type="S3", Location=d["artifact_store"]), )) # Route53 # Outputs return t
'awslogs-region': Ref('AWS::Region'), 'awslogs-stream-prefix': 'ghost' })) ])) ghost_service = t.add_resource( Service('GhostService', Cluster=Ref(cluster), DesiredCount=1, TaskDefinition=Ref(ghost_task_definition), LaunchType='FARGATE', LoadBalancers=[ LoadBalancer(ContainerName='ghost', ContainerPort=2368, TargetGroupArn=ImportValue( Sub("${DependencyStackName}-GhostTG"))) ], NetworkConfiguration=NetworkConfiguration( AwsvpcConfiguration=AwsvpcConfiguration( Subnets=[ ImportValue(Sub("${DependencyStackName}-Subnet1")), ImportValue(Sub("${DependencyStackName}-Subnet2")) ], SecurityGroups=[ ImportValue(Sub("${DependencyStackName}-GhostSG")) ], )))) # Create the required Outputs
DependsOn=[ resource for resource in ["ALBHTTPlistener", "HelloWorldTaskDef", "HelloWorldECSCluster"] ], Cluster=GetAtt(template.resources["HelloWorldECSCluster"], "Arn"), DeploymentConfiguration=DeploymentConfiguration( "HelloWorldECSDeployConf", MaximumPercent=100, MinimumHealthyPercent=0), DesiredCount=1, HealthCheckGracePeriodSeconds=300, LaunchType="FARGATE", LoadBalancers=[ LoadBalancer( "HelloWorldECSServiceLB", ContainerName="hello-world-web", ContainerPort=80, TargetGroupArn=Ref(resources["ALBTargetGroup"]), ) ], NetworkConfiguration=NetworkConfiguration( "HelloWorldNetConf", AwsvpcConfiguration=AwsvpcConfiguration( "HelloWorldVPCConf", AssignPublicIp="DISABLED", SecurityGroups=[ Ref(resources["HelloWorldECSTaskSecurityGroup"]) ], Subnets=[ImportValue("PRVA"), ImportValue("PRVB")])), ServiceName=Join("-", [Ref(parameters["Project"]), "ecs", "service"]), TaskDefinition=Ref(resources["HelloWorldTaskDef"])))