Parameters: ProjectName: Type: String Description: Name for the project VpcCIDR: Type: String Default: 10.0.0.0/16 PublicSubnet1CIDR: Type: String Default: 10.0.0.0/19 PublicSubnet2CIDR: Type: String Default: 10.0.32.0/19 PrivateSubnet1CIDR: Type: String Default: 10.0.64.0/19 PrivateSubnet2CIDR: Type: String Default: 10.0.96.0/19 EnvoyImage: Type: String DJAppImage: Type: String CloudWatchAgentImage: Type: String ContainerPort: Type: Number Default: 8080 GatewayPort: Type: Number Default: 8080 Resources: ################################################### # VPC Resources ################################################### 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 ################################################### # Public Load-Balancer ################################################### PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 Type: network DJAppGatewayTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub '${ProjectName}-gateway' VpcId: !Ref VPC HealthCheckIntervalSeconds: 30 HealthCheckPort: !Ref GatewayPort HealthCheckProtocol: TCP HealthyThresholdCount: 2 UnhealthyThresholdCount: 2 TargetType: ip Port: !Ref GatewayPort Protocol: TCP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 120 PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref DJAppGatewayTargetGroup Type: forward LoadBalancerArn: !Ref PublicLoadBalancer Port: 80 Protocol: TCP ################################################### # CloudMap Resources ################################################### PrivateDnsNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Sub '${ProjectName}.local' Vpc: !Ref VPC DJAppServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: djapp NamespaceId: !GetAtt PrivateDnsNamespace.Id DnsConfig: DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 MetalServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: metal NamespaceId: !GetAtt PrivateDnsNamespace.Id DnsConfig: DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 JazzServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: jazz NamespaceId: !GetAtt PrivateDnsNamespace.Id DnsConfig: DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 ################################################### # Security Group and IAM Roles ################################################### AppSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub 'Security group for the tasks in ${ProjectName}' VpcId: !Ref VPC SecurityGroupIngress: - CidrIp: !Ref VpcCIDR IpProtocol: -1 TaskIAMRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchFullAccess - arn:aws:iam::aws:policy/AWSAppMeshEnvoyAccess TaskExecutionIAMRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: '2012-10-17' 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 ################################################### # Cloudwatch Resources ################################################### LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '${ProjectName}-log-group' RetentionInDays: 30 ################################################### # ECS Cluster, Services & Tasks ################################################### ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ProjectName DJAppGatewayService: Type: AWS::ECS::Service DependsOn: - PublicLoadBalancerListener Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 3 LaunchType: FARGATE NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref DJAppGatewayTaskDef LoadBalancers: - ContainerName: envoy ContainerPort: !Ref GatewayPort TargetGroupArn: !Ref DJAppGatewayTargetGroup DJAppService: Type: AWS::ECS::Service Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 3 LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt DJAppServiceRegistry.Arn NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref DJAppTaskDef MetalV1Service: Type: AWS::ECS::Service Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 2 LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt MetalServiceRegistry.Arn NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref MetalV1TaskDef MetalV2Service: Type: AWS::ECS::Service Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 2 LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt MetalServiceRegistry.Arn NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref MetalV2TaskDef JazzService: Type: AWS::ECS::Service Properties: Cluster: !Ref ECSCluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 2 LaunchType: FARGATE ServiceRegistries: - RegistryArn: !GetAtt JazzServiceRegistry.Arn NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref AppSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 TaskDefinition: !Ref JazzTaskDef DJAppGatewayTaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE NetworkMode: awsvpc Cpu: 256 Memory: 512 TaskRoleArn: !Ref TaskIAMRole ExecutionRoleArn: !Ref TaskExecutionIAMRole ContainerDefinitions: - 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: gateway PortMappings: - ContainerPort: 8125 Protocol: udp Environment: - Name: CW_CONFIG_CONTENT Value: !Sub > { "metrics": { "namespace": "${ProjectName}", "metrics_collected": { "statsd": {} } } } - Name: envoy Image: !Ref EnvoyImage Essential: true Ulimits: - Name: nofile HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: 9901 Protocol: tcp - ContainerPort: !Ref GatewayPort Protocol: tcp HealthCheck: Command: - CMD-SHELL - curl -s http://localhost:9901/ready Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: gateway Environment: - Name: ENVOY_LOG_LEVEL Value: debug - Name: ENABLE_ENVOY_DOG_STATSD Value: 1 - Name: APPMESH_METRIC_EXTENSION_VERSION Value: 1 - Name: APPMESH_RESOURCE_ARN Value: !Ref DJAppGateway DJAppTaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE 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: !Ref ContainerPort - Name: EgressIgnoredIPs Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - 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: djapp PortMappings: - ContainerPort: 8125 Protocol: udp Environment: - Name: CW_CONFIG_CONTENT Value: !Sub > { "metrics": { "namespace": "${ProjectName}", "metrics_collected": { "statsd": {} } } } - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' 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/ready Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: djapp Environment: - Name: ENVOY_LOG_LEVEL Value: debug - Name: ENABLE_ENVOY_DOG_STATSD Value: 1 - Name: APPMESH_METRIC_EXTENSION_VERSION Value: 1 - Name: APPMESH_RESOURCE_ARN Value: !Ref DJAppVirtualNode - Name: app Image: !Ref DJAppImage Essential: true Ulimits: - Name: nofile HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: djapp Environment: - Name: PORT Value: !Ref ContainerPort - Name: BACKENDS Value: !Sub > [ "${JazzVirtualService.VirtualServiceName}:${ContainerPort}", "${MetalVirtualService.VirtualServiceName}:${ContainerPort}" ] JazzTaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE 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: !Ref ContainerPort - Name: EgressIgnoredIPs Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - 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: jazz PortMappings: - ContainerPort: 8125 Protocol: udp Environment: - Name: CW_CONFIG_CONTENT Value: !Sub > { "metrics": { "namespace": "${ProjectName}", "metrics_collected": { "statsd": {} } } } - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' 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/ready Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: jazz Environment: - Name: ENVOY_LOG_LEVEL Value: debug - Name: ENABLE_ENVOY_DOG_STATSD Value: 1 - Name: APPMESH_METRIC_EXTENSION_VERSION Value: 1 - Name: APPMESH_RESOURCE_ARN Value: !Ref JazzVirtualNode - Name: app Image: !Ref DJAppImage Essential: true Ulimits: - Name: nofile HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: jazz Environment: - Name: PORT Value: !Ref ContainerPort - Name: RESPONSES Value: > [ "Astrud Gilberto", "Miles Davis" ] MetalV1TaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE Family: !Sub '${ProjectName}-metal-v1' 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: !Ref ContainerPort - Name: EgressIgnoredIPs Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - 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: metal-v1 PortMappings: - ContainerPort: 8125 Protocol: udp Environment: - Name: CW_CONFIG_CONTENT Value: !Sub > { "metrics": { "namespace": "${ProjectName}", "metrics_collected": { "statsd": {} } } } - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' 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/ready Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: metal-v1 Environment: - Name: ENVOY_LOG_LEVEL Value: debug - Name: ENABLE_ENVOY_DOG_STATSD Value: 1 - Name: APPMESH_METRIC_EXTENSION_VERSION Value: 1 - Name: APPMESH_RESOURCE_ARN Value: !Ref MetalV1VirtualNode - Name: app Image: !Ref DJAppImage Essential: true Ulimits: - Name: nofile HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: metal-v1 Environment: - Name: PORT Value: !Ref ContainerPort - Name: RESPONSES Value: > [ "Megadeth", "Judas Priest" ] MetalV2TaskDef: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE Family: !Sub '${ProjectName}-metal-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: !Ref ContainerPort - Name: EgressIgnoredIPs Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - 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: metal-v2 PortMappings: - ContainerPort: 8125 Protocol: udp Environment: - Name: CW_CONFIG_CONTENT Value: !Sub > { "metrics": { "namespace": "${ProjectName}", "metrics_collected": { "statsd": {} } } } - Name: envoy Image: !Ref EnvoyImage Essential: true User: '1337' 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/ready Interval: 5 Timeout: 10 Retries: 10 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: metal-v2 Environment: - Name: ENVOY_LOG_LEVEL Value: debug - Name: ENABLE_ENVOY_DOG_STATSD Value: 1 - Name: APPMESH_METRIC_EXTENSION_VERSION Value: 1 - Name: APPMESH_RESOURCE_ARN Value: !Ref MetalV2VirtualNode - Name: app Image: !Ref DJAppImage Essential: true Ulimits: - Name: nofile HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: metal-v2 Environment: - Name: PORT Value: !Ref ContainerPort - Name: RESPONSES Value: > [ "Megadeth (Los Angeles, California)", "Judas Priest (West Bromwich, England)" ] ################################################### # App Mesh ################################################### Mesh: Type: AWS::AppMesh::Mesh Properties: MeshName: !Ref ProjectName DJAppGateway: Type: AWS::AppMesh::VirtualGateway Properties: MeshName: !GetAtt Mesh.MeshName VirtualGatewayName: gateway Spec: Listeners: - PortMapping: Port: !Ref GatewayPort Protocol: http DJAppVirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: djapp Spec: Backends: - VirtualService: VirtualServiceName: !GetAtt JazzVirtualService.VirtualServiceName - VirtualService: VirtualServiceName: !GetAtt MetalVirtualService.VirtualServiceName Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.local' ServiceName: !GetAtt DJAppServiceRegistry.Name JazzVirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: jazz Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.local' ServiceName: !GetAtt JazzServiceRegistry.Name MetalV1VirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: metal-v1 Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.local' ServiceName: !GetAtt MetalServiceRegistry.Name Attributes: - Key: ECS_TASK_DEFINITION_FAMILY Value: !Sub '${ProjectName}-metal-v1' MetalV2VirtualNode: Type: AWS::AppMesh::VirtualNode Properties: MeshName: !GetAtt Mesh.MeshName VirtualNodeName: metal-v2 Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http ServiceDiscovery: AWSCloudMap: NamespaceName: !Sub '${ProjectName}.local' ServiceName: !GetAtt MetalServiceRegistry.Name Attributes: - Key: ECS_TASK_DEFINITION_FAMILY Value: !Sub '${ProjectName}-metal-v2' DJAppVirtualService: Type: AWS::AppMesh::VirtualService Properties: MeshName: !GetAtt Mesh.MeshName VirtualServiceName: !Sub '${DJAppServiceRegistry.Name}.${ProjectName}.local' Spec: Provider: VirtualNode: VirtualNodeName: !GetAtt DJAppVirtualNode.VirtualNodeName JazzVirtualService: Type: AWS::AppMesh::VirtualService Properties: MeshName: !GetAtt Mesh.MeshName VirtualServiceName: !Sub '${JazzServiceRegistry.Name}.${ProjectName}.local' Spec: Provider: VirtualNode: VirtualNodeName: !GetAtt JazzVirtualNode.VirtualNodeName MetalVirtualService: Type: AWS::AppMesh::VirtualService Properties: MeshName: !GetAtt Mesh.MeshName VirtualServiceName: !Sub '${MetalServiceRegistry.Name}.${ProjectName}.local' Spec: Provider: VirtualRouter: VirtualRouterName: !GetAtt MetalVirtualRouter.VirtualRouterName MetalVirtualRouter: Type: AWS::AppMesh::VirtualRouter Properties: MeshName: !GetAtt Mesh.MeshName VirtualRouterName: metal Spec: Listeners: - PortMapping: Port: !Ref ContainerPort Protocol: http MetalRoute: Type: AWS::AppMesh::Route Properties: MeshName: !GetAtt Mesh.MeshName VirtualRouterName: !GetAtt MetalVirtualRouter.VirtualRouterName RouteName: metal Spec: HttpRoute: Match: Prefix: / Action: WeightedTargets: - VirtualNode: !GetAtt MetalV1VirtualNode.VirtualNodeName Weight: 60 - VirtualNode: !GetAtt MetalV2VirtualNode.VirtualNodeName Weight: 40 DJAppGatewayRoute: Type: AWS::AppMesh::GatewayRoute Properties: MeshName: !GetAtt Mesh.MeshName VirtualGatewayName: !GetAtt DJAppGateway.VirtualGatewayName GatewayRouteName: djapp Spec: HttpRoute: Match: Prefix: / Action: Target: VirtualService: VirtualServiceName: !GetAtt DJAppVirtualService.VirtualServiceName Outputs: PublicEndpoint: Value: !Sub 'http://${PublicLoadBalancer.DNSName}' Export: Name: !Sub '${ProjectName}:PublicEndpoint'