Parameters: ProjectName: Type: String Description: Project name to link stacks VpcCIDR: Description: Please enter the IP range (CIDR notation) for this VPC Type: String Default: 10.0.0.0/16 PublicSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone Type: String Default: 10.0.0.0/19 PublicSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone Type: String Default: 10.0.32.0/19 PrivateSubnet1CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone Type: String Default: 10.0.64.0/19 PrivateSubnet2CIDR: Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone Type: String Default: 10.0.96.0/19 ColorAppImage: Type: String Description: Color app container image FrontAppImage: Type: String Description: Front app container image EnvoyImage: Type: String Description: Envoy container image CloudWatchAgentImage: Type: String Description: Cloud Watch agent container image ContainerPort: Type: Number Description: Port number to use for applications Default: 8080 Resources: # START infra ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ProjectName VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsHostnames: true Tags: - Key: Name Value: !Ref ProjectName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref ProjectName InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PublicSubnet1CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${ProjectName} Public Subnet (AZ1)' PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PublicSubnet2CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${ProjectName} Public Subnet (AZ2)' PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet1CIDR MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub '${ProjectName} Private Subnet (AZ1)' PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: !Ref PrivateSubnet2CIDR MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Sub '${ProjectName} Private Subnet (AZ2)' NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${ProjectName} Public Routes' DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${ProjectName} Private Routes (AZ1)' DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${ProjectName} Private Routes (AZ2)' DefaultPrivateRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable2 SubnetId: !Ref PrivateSubnet2 AppSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: "Security group for the apps" VpcId: !Ref VPC SecurityGroupIngress: - CidrIp: !Ref VpcCIDR IpProtocol: -1 LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '${ProjectName}-log-group' RetentionInDays: 30 TaskIamRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: | { "Statement": [{ "Effect": "Allow", "Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]}, "Action": [ "sts:AssumeRole" ] }] } ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchFullAccess - arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess - arn:aws:iam::aws:policy/AWSAppMeshEnvoyAccess TaskExecutionIamRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: | { "Statement": [{ "Effect": "Allow", "Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]}, "Action": [ "sts:AssumeRole" ] }] } ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess PrivateDnsNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Sub '${ProjectName}.pvtdns' Vpc: !Ref VPC Mesh: Type: AWS::AppMesh::Mesh Properties: MeshName: !Ref ProjectName AppMeshHostedZone: Type: AWS::Route53::HostedZone Properties: Name: !Sub '${ProjectName}.mesh.local' HostedZoneConfig: Comment: Private hosted zone for resolving virtual-services VPCs: - VPCId: !Ref VPC VPCRegion: !Ref 'AWS::Region' AppMeshWildcardRecordSet: Type: AWS::Route53::RecordSet DependsOn: - AppMeshHostedZone Properties: HostedZoneId: !Ref AppMeshHostedZone ResourceRecords: - '1.2.3.4' TTL: '900' Name: Fn::Join: - '.' - - '*' - !Sub '${ProjectName}.mesh.local' Type: A # END infra # START colorapp ColorServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: 'color' DnsConfig: NamespaceId: !GetAtt PrivateDnsNamespace.Id DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 ColorTaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - 'FARGATE' Family: !Sub '${ProjectName}-color' NetworkMode: 'awsvpc' Cpu: 256 Memory: 512 TaskRoleArn: !Ref TaskIamRole ExecutionRoleArn: !Ref TaskExecutionIamRole ProxyConfiguration: Type: 'APPMESH' ContainerName: 'envoy' ProxyConfigurationProperties: - Name: 'IgnoredUID' Value: '1337' - Name: 'ProxyIngressPort' Value: '15000' - Name: 'ProxyEgressPort' Value: '15001' - Name: 'AppPorts' Value: !Sub '${ContainerPort}' - Name: 'EgressIgnoredIPs' Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - Name: 'app' Image: !Ref ColorAppImage Essential: true DependsOn: - ContainerName: 'envoy' Condition: 'HEALTHY' - ContainerName: 'xray' Condition: 'START' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' PortMappings: - ContainerPort: !Ref ContainerPort HostPort: !Ref ContainerPort Protocol: 'tcp' Environment: - Name: COLOR Value: 'green' - Name: PORT Value: !Sub '${ContainerPort}' - Name: XRAY_APP_NAME Value: 'color' - Name: 'xray' Image: "public.ecr.aws/xray/aws-xray-daemon" Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' PortMappings: - ContainerPort: 2000 Protocol: 'udp' - Name: 'cwagent' Image: !Ref CloudWatchAgentImage Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'cwagent' PortMappings: - ContainerPort: 8125 Protocol: 'udp' Environment: - Name: 'HOST_NAME' Value: !GetAtt ColorVirtualNode.VirtualNodeName - Name: CW_CONFIG_CONTENT Value: Fn::Sub: "{ \"metrics\": { \"namespace\":\"${ProjectName}\", \"metrics_collected\": { \"statsd\": {}}}}" - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' DependsOn: - ContainerName: 'xray' Condition: 'START' Ulimits: - Name: "nofile" HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: 9901 Protocol: 'tcp' - ContainerPort: 15000 Protocol: 'tcp' - ContainerPort: 15001 Protocol: 'tcp' HealthCheck: Command: - 'CMD-SHELL' - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' Environment: - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' - Name: 'ENABLE_ENVOY_XRAY_TRACING' Value: '1' - Name: 'ENABLE_ENVOY_STATS_TAGS' Value: '1' - Name: 'ENABLE_ENVOY_DOG_STATSD' Value: '1' - Name: 'APPMESH_RESOURCE_ARN' Value: Fn::Join: - '' - - 'mesh/' - !GetAtt Mesh.MeshName - '/virtualNode/' - !GetAtt ColorVirtualNode.VirtualNodeName ColorECSService: Type: AWS::ECS::Service DependsOn: - ColorServiceRegistry Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 3 LaunchType: 'FARGATE' ServiceRegistries: - RegistryArn: !GetAtt 'ColorServiceRegistry.Arn' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref ColorTaskDef ColorVirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: !Sub '${ProjectName}-color-node' Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.pvtdns' ServiceName: !GetAtt ColorServiceRegistry.Name Attributes: - Key: 'ECS_TASK_DEFINITION_FAMILY' Value: !Sub '${ProjectName}-color' # colorapp v2 (blue) ColorV2TaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - 'FARGATE' Family: !Sub '${ProjectName}-color-v2' NetworkMode: 'awsvpc' Cpu: 256 Memory: 512 TaskRoleArn: !Ref TaskIamRole ExecutionRoleArn: !Ref TaskExecutionIamRole ProxyConfiguration: Type: 'APPMESH' ContainerName: 'envoy' ProxyConfigurationProperties: - Name: 'IgnoredUID' Value: '1337' - Name: 'ProxyIngressPort' Value: '15000' - Name: 'ProxyEgressPort' Value: '15001' - Name: 'AppPorts' Value: !Sub '${ContainerPort}' - Name: 'EgressIgnoredIPs' Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - Name: 'app' Image: !Ref ColorAppImage Essential: true DependsOn: - ContainerName: 'envoy' Condition: 'HEALTHY' - ContainerName: 'xray' Condition: 'START' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' PortMappings: - ContainerPort: !Ref ContainerPort HostPort: !Ref ContainerPort Protocol: 'tcp' Environment: - Name: COLOR Value: 'blue' - Name: PORT Value: !Sub '${ContainerPort}' - Name: XRAY_APP_NAME Value: 'color-v2' - Name: 'xray' Image: "public.ecr.aws/xray/aws-xray-daemon" Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' PortMappings: - ContainerPort: 2000 Protocol: 'udp' - Name: 'cwagent' Image: !Ref CloudWatchAgentImage Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'cwagent' PortMappings: - ContainerPort: 8125 Protocol: 'udp' Environment: - Name: 'HOST_NAME' Value: !GetAtt ColorV2VirtualNode.VirtualNodeName - Name: CW_CONFIG_CONTENT Value: Fn::Sub: "{ \"metrics\": { \"namespace\":\"${ProjectName}\", \"metrics_collected\": { \"statsd\": {}}}}" - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' DependsOn: - ContainerName: 'xray' Condition: 'START' Ulimits: - Name: "nofile" HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: 9901 Protocol: 'tcp' - ContainerPort: 15000 Protocol: 'tcp' - ContainerPort: 15001 Protocol: 'tcp' HealthCheck: Command: - 'CMD-SHELL' - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'color' Environment: - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' - Name: 'ENABLE_ENVOY_XRAY_TRACING' Value: '1' - Name: 'ENABLE_ENVOY_STATS_TAGS' Value: '1' - Name: 'ENABLE_ENVOY_DOG_STATSD' Value: '1' - Name: 'APPMESH_RESOURCE_ARN' Value: Fn::Join: - '' - - 'mesh/' - !GetAtt Mesh.MeshName - '/virtualNode/' - !GetAtt ColorV2VirtualNode.VirtualNodeName ColorV2ECSService: Type: AWS::ECS::Service DependsOn: - ColorServiceRegistry Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 3 LaunchType: 'FARGATE' ServiceRegistries: - RegistryArn: !GetAtt 'ColorServiceRegistry.Arn' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref ColorV2TaskDef ColorV2VirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: !Sub '${ProjectName}-color-v2-node' Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.pvtdns' ServiceName: !GetAtt ColorServiceRegistry.Name Attributes: - Key: 'ECS_TASK_DEFINITION_FAMILY' Value: !Sub '${ProjectName}-color-v2' ColorVirtualService: Type: AWS::AppMesh::VirtualService Properties: MeshName: !GetAtt Mesh.MeshName VirtualServiceName: Fn::Join: - '.' - - !GetAtt ColorServiceRegistry.Name - !Sub '${ProjectName}.mesh.local' Spec: Provider: VirtualRouter: VirtualRouterName: !GetAtt ColorVirtualRouter.VirtualRouterName ColorVirtualRouter: Type: AWS::AppMesh::VirtualRouter Properties: MeshName: !GetAtt Mesh.MeshName VirtualRouterName: !Sub '${ProjectName}-color-router' Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ColorRoute: Type: AWS::AppMesh::Route Properties: MeshName: !GetAtt Mesh.MeshName VirtualRouterName: !GetAtt ColorVirtualRouter.VirtualRouterName RouteName: !Sub '${ProjectName}-color-route' Spec: HttpRoute: Match: Prefix: '/' Action: WeightedTargets: - VirtualNode: !GetAtt ColorVirtualNode.VirtualNodeName Weight: 50 - VirtualNode: !GetAtt ColorV2VirtualNode.VirtualNodeName Weight: 50 # END colorapp # START feapp FrontTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 60 HealthCheckPath: '/ping' HealthCheckPort: !Ref ContainerPort HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 TargetType: ip Name: !Sub '${ProjectName}-front' Port: !Ref ContainerPort Protocol: HTTP UnhealthyThresholdCount: 2 TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 120 VpcId: !Ref VPC FrontVirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: !Sub "${ProjectName}-front-node" Spec: Listeners: - PortMapping: Port: !Sub '${ContainerPort}' Protocol: http ServiceDiscovery: DNS: Hostname: !GetAtt PublicLoadBalancer.DNSName Backends: - VirtualService: VirtualServiceName: !GetAtt ColorVirtualService.VirtualServiceName FrontTaskDef: Type: AWS::ECS::TaskDefinition DependsOn: - FrontVirtualNode Properties: RequiresCompatibilities: - 'FARGATE' Family: !Sub '${ProjectName}-front' NetworkMode: 'awsvpc' Cpu: 256 Memory: 512 TaskRoleArn: !Ref TaskIamRole ExecutionRoleArn: !Ref TaskExecutionIamRole ProxyConfiguration: Type: 'APPMESH' ContainerName: 'envoy' ProxyConfigurationProperties: - Name: 'IgnoredUID' Value: '1337' - Name: 'ProxyIngressPort' Value: '15000' - Name: 'ProxyEgressPort' Value: '15001' - Name: 'AppPorts' Value: !Sub '${ContainerPort}' - Name: 'EgressIgnoredIPs' Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - Name: 'app' Image: !Ref FrontAppImage Essential: true LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'front' PortMappings: - ContainerPort: !Ref ContainerPort Protocol: 'tcp' DependsOn: - ContainerName: 'envoy' Condition: 'HEALTHY' - ContainerName: 'xray' Condition: 'START' Environment: - Name: 'COLOR_HOST' Value: Fn::Join: - '' - - !GetAtt ColorVirtualService.VirtualServiceName - ':' - !Sub '${ContainerPort}' - Name: PORT Value: !Sub '${ContainerPort}' - Name: XRAY_APP_NAME Value: 'front' - Name: 'xray' Image: "public.ecr.aws/xray/aws-xray-daemon" Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'front' PortMappings: - ContainerPort: 2000 Protocol: 'udp' - Name: 'cwagent' Image: !Ref CloudWatchAgentImage Essential: true User: '1337' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'cwagent' PortMappings: - ContainerPort: 8125 Protocol: 'udp' Environment: - Name: 'HOST_NAME' Value: !GetAtt FrontVirtualNode.VirtualNodeName - Name: CW_CONFIG_CONTENT Value: Fn::Sub: "{ \"metrics\": { \"namespace\":\"${ProjectName}\", \"metrics_collected\": { \"statsd\": {}}}}" - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' DependsOn: - ContainerName: 'xray' Condition: 'START' Ulimits: - Name: "nofile" HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: 9901 Protocol: 'tcp' - ContainerPort: 15000 Protocol: 'tcp' - ContainerPort: 15001 Protocol: 'tcp' HealthCheck: Command: - 'CMD-SHELL' - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'front' Environment: - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' - Name: 'ENABLE_ENVOY_XRAY_TRACING' Value: '1' - Name: 'ENABLE_ENVOY_STATS_TAGS' Value: '1' - Name: 'ENABLE_ENVOY_DOG_STATSD' Value: '1' - Name: 'APPMESH_RESOURCE_ARN' Value: Fn::Join: - '' - - 'mesh/' - !GetAtt Mesh.MeshName - '/virtualNode/' - !GetAtt FrontVirtualNode.VirtualNodeName FrontECSService: Type: AWS::ECS::Service DependsOn: - PublicLoadBalancerListener - FrontListenerRule Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 3 LaunchType: 'FARGATE' TaskDefinition: !Ref FrontTaskDef LoadBalancers: - ContainerName: app ContainerPort: !Ref ContainerPort TargetGroupArn: !Ref FrontTargetGroup NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 # END feapp # START public-lb SecurityGroupIngressFromPublicLB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the public LB GroupId: !Ref AppSecurityGroup IpProtocol: -1 SourceSecurityGroupId: !Ref PublicLoadBalancerSecurityGroup PublicLoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: 'Access to the public facing load balancer' VpcId: !Ref VPC SecurityGroupIngress: - CidrIp: 0.0.0.0/0 IpProtocol: tcp FromPort: 80 ToPort: 80 PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref PublicLoadBalancerSecurityGroup PublicLoadBalancerListener: DependsOn: - PublicLoadBalancer Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref FrontTargetGroup Type: 'forward' LoadBalancerArn: !Ref PublicLoadBalancer Port: 80 Protocol: HTTP FrontListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref FrontTargetGroup Type: 'forward' Conditions: - Field: path-pattern Values: - '/color' ListenerArn: !Ref PublicLoadBalancerListener Priority: 10 # END public-lb Outputs: FrontEndpoint: Description: 'Public endpoint for Front service' Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']] Export: Name: !Sub "${ProjectName}:FrontEndpoint"