--- Parameters: AppMeshXdsEndpoint: Type: String Description: App Mesh XDS Endpoint Override (normally don't set this) Default: "" EnvoyImage: Type: String Description: Envoy container image ColorTellerImage: Type: String Description: Color Teller container image LaunchType: Type: String Description: ECS Task Launch Type Default: FARGATE Resources: Cluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref AWS::StackName SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: "Security group for the instances" VpcId: Fn::ImportValue: !Sub '${AWS::StackName}-vpc:VPC' SecurityGroupIngress: - CidrIp: Fn::ImportValue: !Sub '${AWS::StackName}-vpc:VpcCIDR' IpProtocol: -1 LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '${AWS::StackName}-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/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 CloudMapNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Sub '${AWS::StackName}-mesh.local' Vpc: Fn::ImportValue: !Sub "${AWS::StackName}-vpc:VPC" ColorTellerServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: 'colorteller' DnsConfig: NamespaceId: !GetAtt 'CloudMapNamespace.Id' DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 ColorGatewayServiceRegistry: Type: AWS::ServiceDiscovery::Service Properties: Name: 'colorgateway' DnsConfig: NamespaceId: !GetAtt 'CloudMapNamespace.Id' DnsRecords: - Type: A TTL: 300 HealthCheckCustomConfig: FailureThreshold: 1 PublicLoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: 'Access to the public facing load balancer' VpcId: Fn::ImportValue: !Sub "${AWS::StackName}-vpc: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: - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PublicSubnet1' - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PublicSubnet2' SecurityGroups: - !Ref PublicLoadBalancerSecurityGroup WebTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 6 HealthCheckPath: '/ping' HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 TargetType: ip Name: !Sub '${AWS::StackName}-webtarget' Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 120 VpcId: Fn::ImportValue: !Sub "${AWS::StackName}-vpc:VPC" PublicLoadBalancerListener: DependsOn: - PublicLoadBalancer Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref WebTargetGroup Type: 'forward' LoadBalancerArn: !Ref PublicLoadBalancer Port: 80 Protocol: HTTP WebLoadBalancerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref WebTargetGroup Type: 'forward' Conditions: - Field: path-pattern Values: - '*' ListenerArn: !Ref PublicLoadBalancerListener Priority: 1 ColorGatewayTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - !Ref LaunchType Family: 'colorgateway' NetworkMode: 'awsvpc' Cpu: 256 Memory: 512 TaskRoleArn: !Ref TaskIamRole ExecutionRoleArn: !Ref TaskExecutionIamRole ContainerDefinitions: - Name: envoy Image: !Ref EnvoyImage Essential: true Ulimits: - Name: "nofile" HardLimit: 15000 SoftLimit: 15000 PortMappings: - ContainerPort: 9901 Protocol: 'tcp' - ContainerPort: 15000 Protocol: 'tcp' - ContainerPort: 15001 Protocol: 'tcp' - ContainerPort: 9080 Protocol: 'tcp' HealthCheck: Command: - 'CMD-SHELL' - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 2 Retries: 3 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub '${AWS::StackName}-log-group' awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'colorgateway' Environment: - Name: 'APPMESH_RESOURCE_ARN' Value: !Sub 'mesh/${AWS::StackName}-mesh/virtualGateway/colorgateway' - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' BlueColorTellerTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - !Ref LaunchType Family: 'blue' 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: '9080' - Name: 'EgressIgnoredIPs' Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - Name: 'app' Image: !Ref ColorTellerImage Essential: true DependsOn: - ContainerName: "envoy" Condition: "HEALTHY" LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub ${AWS::StackName}-log-group awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'blue' PortMappings: - ContainerPort: 9080 Protocol: 'tcp' Environment: - Name: "COLOR" Value: "blue" - Name: "SERVER_PORT" Value: "9080" - Name: "STAGE" Value: "" - 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/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 2 Retries: 3 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub '${AWS::StackName}-log-group' awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'blue' Environment: - Name: 'APPMESH_RESOURCE_ARN' Value: !Sub 'mesh/${AWS::StackName}-mesh/virtualNode/colorteller-blue-node' - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' GreenColorTellerTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - !Ref LaunchType Family: 'green' 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: '9080' - Name: 'EgressIgnoredIPs' Value: '169.254.170.2,169.254.169.254' ContainerDefinitions: - Name: 'app' Image: !Ref ColorTellerImage Essential: true DependsOn: - ContainerName: "envoy" Condition: "HEALTHY" LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub '${AWS::StackName}-log-group' awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'green' PortMappings: - ContainerPort: 9080 Protocol: 'tcp' Environment: - Name: "COLOR" Value: "green" - Name: "SERVER_PORT" Value: "9080" - Name: "STAGE" Value: "" - 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/server_info | grep state | grep -q LIVE' Interval: 5 Timeout: 2 Retries: 3 LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub '${AWS::StackName}-log-group' awslogs-region: !Ref AWS::Region awslogs-stream-prefix: 'green' Environment: - Name: 'APPMESH_RESOURCE_ARN' Value: !Sub 'mesh/${AWS::StackName}-mesh/virtualNode/colorteller-green-node' - Name: 'ENVOY_LOG_LEVEL' Value: 'debug' ColorGatewayService: Type: AWS::ECS::Service DependsOn: - WebLoadBalancerRule Properties: Cluster: !Ref Cluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 1 LaunchType: !Ref LaunchType ServiceRegistries: - RegistryArn: !GetAtt 'ColorGatewayServiceRegistry.Arn' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref SecurityGroup Subnets: - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet1' - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet2' TaskDefinition: !Ref ColorGatewayTaskDefinition LoadBalancers: - ContainerName: envoy ContainerPort: 9080 TargetGroupArn: !Ref WebTargetGroup BlueColorTellerService: Type: AWS::ECS::Service Properties: Cluster: !Ref Cluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 1 LaunchType: !Ref LaunchType ServiceRegistries: - RegistryArn: !GetAtt 'ColorTellerServiceRegistry.Arn' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref SecurityGroup Subnets: - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet1' - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet2' TaskDefinition: !Ref BlueColorTellerTaskDefinition GreenColorTellerService: Type: AWS::ECS::Service Properties: Cluster: !Ref Cluster DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DesiredCount: 1 LaunchType: !Ref LaunchType ServiceRegistries: - RegistryArn: !GetAtt 'ColorTellerServiceRegistry.Arn' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref SecurityGroup Subnets: - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet1' - Fn::ImportValue: !Sub '${AWS::StackName}-vpc:PrivateSubnet2' TaskDefinition: !Ref GreenColorTellerTaskDefinition Outputs: ColorGatewayEndpoint: Description: 'Public endpoint for Color Gateway service' Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']] Export: Name: !Sub '${AWS::StackName}:ColorGatewayEndpoint'