AWSTemplateFormatVersion: '2010-09-09' Description: Deploy a service on AWS Fargate, hosted in a public subnet, accessible via a public load balancer. Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Container Configuration" Parameters: - ImageUrl - ContainerPort - ContainerCpu - ContainerMemory - Label: default: "Networking" Parameters: - Path - HealthCheckPath - Label: default: "Service parameters" Parameters: - EnvironmentName - ServiceName - Priority - DesiredCount - MaximumPercent - MinimumHealthyPercent Parameters: EnvironmentName: Type: String Default: dev Description: The name of the environment to add this service to ServiceName: Type: String Default: appconfig-test Description: A name for the service ImageUrl: Type: String Default: "" Description: Provide the url of a docker image that was pushed to the ECR that contains the application process that will handle the traffic for this service ContainerPort: Type: Number Default: 80 Description: What port number the application inside the docker container is binding to ContainerCpu: Type: Number Default: 256 Description: How much CPU to give the container. 1024 is 1 CPU AllowedValues: - 1024 - 512 - 256 ContainerMemory: Type: Number Default: 512 Description: How much memory in megabytes to give the container AllowedValues: - 2048 - 1024 - 512 Path: Type: String Default: "*" Description: A path on the load balancer that this service should be connected to. Use * to send all load balancer traffic to this service. HealthCheckPath: Type: String Default: "/movies/getMovies" Description: A Valid path on the service which the Healthcheck will ping to get a valid 200 Response Priority: Type: Number Default: 1 Description: The priority for the routing rule added to the load balancer. This only applies if your have multiple services which have been assigned to different paths on the load balancer. DesiredCount: Type: Number Default: 2 Description: How many copies of the service task to run MaximumPercent: Type: Number Default: 200 Description: Upper limit on the number of tasks in a service that are allowed in the RUNNING or PENDING state during a deployment, as a percentage of the desired number of tasks MinimumHealthyPercent: Type: Number Default: 75 Description: Lower limit on the number of tasks in a service that must remain in the RUNNING state during a deployment, as a percentage of the desired number of tasks Resources: EcsSecurityGroupIngressFromPublicALB: Type: AWS::EC2::SecurityGroupIngress Properties: Description: Ingress from the public ALB GroupId: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:ContainerSecurityGroup IpProtocol: tcp SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG' FromPort: 80 ToPort: 80 PublicLoadBalancerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the public facing load balancer VpcId: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:VpcId SecurityGroupIngress: # Allow access to ALB from anywhere on the internet - 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: # The load balancer is placed into the public subnets, so that traffic # from the internet can reach the load balancer directly via the internet gateway - Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:PublicSubnetOne - Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:PublicSubnetTwo SecurityGroups: [!Ref 'PublicLoadBalancerSG'] Tags: - Key: "Name" Value: !Sub ${ServiceName}:LB # A dummy target group is used to setup the ALB to just drop traffic # initially, before any real service target groups have been added. DummyTargetGroupPublic: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 6 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:VpcId PublicLoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - TargetGroupArn: !Ref 'DummyTargetGroupPublic' Type: 'forward' LoadBalancerArn: !Ref 'PublicLoadBalancer' Port: 80 Protocol: HTTP # A log group for storing the stdout logs from this service's containers LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub AppConfigBlog-${EnvironmentName}-service-${ServiceName} # The task definition. This is a simple metadata description of what # container to run, and what resource requirements it has. TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref 'ServiceName' Cpu: !Ref 'ContainerCpu' Memory: !Ref 'ContainerMemory' NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:ECSTaskExecutionRole TaskRoleArn: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:ECSRole ContainerDefinitions: - Name: !Ref 'ServiceName' Cpu: !Ref 'ContainerCpu' Memory: !Ref 'ContainerMemory' Image: !Ref 'ImageUrl' PortMappings: - ContainerPort: !Ref 'ContainerPort' LogConfiguration: LogDriver: 'awslogs' Options: awslogs-group: !Sub AppConfigBlog-${EnvironmentName}-service-${ServiceName} awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: !Ref 'ServiceName' # The service. The service is a resource which allows you to run multiple # copies of a type of task, and gather up their logs and metrics, as well # as monitor the number of running tasks and replace any that have crashed Service: Type: AWS::ECS::Service DependsOn: LoadBalancerRule Properties: ServiceName: !Ref 'ServiceName' Cluster: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:ClusterName LaunchType: FARGATE DeploymentConfiguration: MaximumPercent: !Ref 'MaximumPercent' MinimumHealthyPercent: !Ref 'MinimumHealthyPercent' DesiredCount: !Ref 'DesiredCount' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:ContainerSecurityGroup Subnets: - Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:PublicSubnetOne - Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:PublicSubnetTwo TaskDefinition: !Ref 'TaskDefinition' LoadBalancers: - ContainerName: !Ref 'ServiceName' ContainerPort: !Ref 'ContainerPort' TargetGroupArn: !Ref 'TargetGroup' # A target group. This is used for keeping track of all the tasks, and # what IP addresses / port numbers they have. You can query it yourself, # to use the addresses yourself, but most often this target group is just # connected to an application load balancer, or network load balancer, so # it can automatically distribute traffic across all the targets. TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 40 HealthCheckPath: !Ref 'HealthCheckPath' HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 30 HealthyThresholdCount: 2 TargetType: ip Name: !Ref 'ServiceName' Port: !Ref 'ContainerPort' Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: Fn::ImportValue: !Sub AppConfigBlog:${EnvironmentName}:VpcId # Create a rule on the load balancer for routing traffic to the target group LoadBalancerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - TargetGroupArn: !Ref 'TargetGroup' Type: 'forward' Conditions: - Field: path-pattern Values: [!Ref 'Path'] ListenerArn: !Ref PublicLoadBalancerListener Priority: !Ref 'Priority' Outputs: ExternalUrl: Description: The url of the external load balancer Value: !Sub http://${PublicLoadBalancer.DNSName} Export: Name: !Sub AppConfigBlog:${EnvironmentName}:ExternalUrl