Description: > This template deploys an empty ECS Cluster and a mesh(AppMesh), Public ALB, Security Groups, CloudMap Namespace and Static entries for Virtual Services. Parameters: EnvironmentName: Description: An environment name that will be prefixed to resource names Type: String EnvoyImage: Description: App Mesh Envoy container image. See https://docs.aws.amazon.com/app-mesh/latest/userguide/envoy.html. Type: String Namespace: Type: String Default: yelb.local ContainerPort: Type: Number Default: 80 LoadBalancerPort: Type: Number Default: 80 CountOfGatewayTasks: Description: The number of tasks to be instantiated for the Gateway service Type: Number Default: 1 LoadBalancerPath: Type: String Default: "*" Description: A path on the public load balancer that this service should be connected to. Use * to send all load balancer traffic to this service. Resources: #------ ECS Resources ------# #ECS Cluster Cluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref EnvironmentName ClusterSettings: - Name: containerInsights Value: enabled #ECS Task Execution Role ExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Join ['-', [!Ref EnvironmentName, ExecutionRole]] AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' #ECS Task Role TaskRole: Type: AWS::IAM::Role Properties: RoleName: !Join ['-', [!Ref EnvironmentName, TaskRole]] 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' #ECS Container SecurityGroup ContainerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Join ['-', [!Ref EnvironmentName, ContainerSecurityGroup]] VpcId: 'Fn::ImportValue': !Sub "${EnvironmentName}:VPC" SecurityGroupIngress: - IpProtocol: tcp CidrIp: '0.0.0.0/0' FromPort: 1025 ToPort: 65535 - IpProtocol: tcp FromPort: !Ref ContainerPort ToPort: !Ref ContainerPort SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup #------ Load Balancing Resources ------# #Load Balancing Security Group LoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Join ['-', [!Ref EnvironmentName, LoadBalancerSecurityGroup]] VpcId: 'Fn::ImportValue': !Sub "${EnvironmentName}:VPC" SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref LoadBalancerPort ToPort: !Ref LoadBalancerPort CidrIp: 0.0.0.0/0 #Load Balancer PublicLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing Subnets: - { 'Fn::ImportValue': !Sub "${EnvironmentName}:PublicSubnet1" } - { 'Fn::ImportValue': !Sub "${EnvironmentName}:PublicSubnet2" } SecurityGroups: [!Ref 'LoadBalancerSecurityGroup'] #Load Balancer Listener PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener DependsOn: - PublicLoadBalancer Properties: DefaultActions: - TargetGroupArn: !Ref TargetGroup Type: 'forward' LoadBalancerArn: !Ref 'PublicLoadBalancer' Port: 80 Protocol: HTTP #Load Balancer TargetGroup TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 6 HealthCheckPath: '/' HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 TargetType: ip Name: !Sub 'yelb-targetgroup' Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 120 VpcId: Fn::ImportValue: !Sub '${EnvironmentName}:VPC' #Load Balancer Rule(s) LoadBalancerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref TargetGroup Type: 'forward' Conditions: - Field: path-pattern Values: [!Ref 'LoadBalancerPath'] ListenerArn: !Ref PublicLoadBalancerListener Priority: 1 #------ CloudMap Resources ------# #CloudMap Namespace CloudMapNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Ref 'Namespace' Vpc: Fn::ImportValue: !Sub "${EnvironmentName}:VPC" Description: !Sub "Service Discovery Namespace for Yelb" #Mesh Resource Mesh: Type: AWS::AppMesh::Mesh Properties: MeshName: !Ref EnvironmentName #To workaround the issue on AppMesh: https://github.com/aws/aws-app-mesh-roadmap/issues/65 YelbUIStaticServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Name: yelb-ui DnsConfig: DnsRecords: - Type: A TTL: "10" NamespaceId: !Ref 'CloudMapNamespace' YelbUIIPStaticEntry: Type: AWS::ServiceDiscovery::Instance Properties: InstanceAttributes: AWS_INSTANCE_IPV4: 10.10.10.10 ServiceId: !Ref YelbUIStaticServiceDiscoveryEntry YelbAppServerStaticServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Name: yelb-appserver DnsConfig: DnsRecords: - Type: A TTL: "10" NamespaceId: !Ref 'CloudMapNamespace' YelbAppServerIPStaticEntry: Type: AWS::ServiceDiscovery::Instance Properties: InstanceAttributes: AWS_INSTANCE_IPV4: 10.10.10.10 ServiceId: !Ref YelbAppServerStaticServiceDiscoveryEntry YelbRedisStaticServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Name: yelb-redisserver DnsConfig: DnsRecords: - Type: A TTL: "10" NamespaceId: !Ref 'CloudMapNamespace' YelbRedisIPStaticEntry: Type: AWS::ServiceDiscovery::Instance Properties: InstanceAttributes: AWS_INSTANCE_IPV4: 10.10.10.10 ServiceId: !Ref YelbRedisStaticServiceDiscoveryEntry YelbDBStaticServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Name: yelb-db DnsConfig: DnsRecords: - Type: A TTL: "10" NamespaceId: !Ref 'CloudMapNamespace' YelbDBStaticEntry: Type: AWS::ServiceDiscovery::Instance Properties: InstanceAttributes: AWS_INSTANCE_IPV4: 10.10.10.10 ServiceId: !Ref YelbDBStaticServiceDiscoveryEntry Outputs: Mesh: Description: A reference to the AppMesh Mesh Value: !GetAtt Mesh.MeshName Export: Name: !Sub "${EnvironmentName}:Mesh" ExecutionRole: Description: A reference to the Task Execution Role Value: !GetAtt ExecutionRole.Arn Export: Name: !Sub "${EnvironmentName}:ExecutionRole" TaskRole: Description: A reference to the TaskRole Value: !GetAtt TaskRole.Arn Export: Name: !Sub "${EnvironmentName}:TaskRole" ContainerSecurityGroup: Description: A reference to the ContainerSecurityGroup Value: !Ref ContainerSecurityGroup Export: Name: !Sub "${EnvironmentName}:ContainerSecurityGroup" Namespace: Description: A reference to the Namespace Value: !GetAtt 'CloudMapNamespace.Id' Export: Name: !Sub "${EnvironmentName}:CloudMapNamespaceId" PublicLoadBalancer: Description: A reference to the LoadBalancer DNSName Value: !GetAtt PublicLoadBalancer.DNSName Export: Name: !Sub "${EnvironmentName}:PublicLoadBalancer" TargetGroupArn: Description: A reference to the TargetGroup Value: !Ref TargetGroup Export: Name: !Sub "${EnvironmentName}:TargetGroupArn"