AWSTemplateFormatVersion: '2010-09-09' Description: EC2 ECS cluster running containers in public or private subnets. Parameters: EnvironmentName: Type: String Default: production Description: A friendly environment name that will be used for namespacing all cluster resources, for example staging, qa, or production LaunchType: Type: String Default: Fargate AllowedValues: [Fargate, EC2] InstanceType: Type: String Default: t2.micro Description: Class of EC2 instance used to host containers AllowedValues: [ t2.micro, t2.small, t2.medium, t2.large, t2.xlarge, t2.2xlarge ] ECSAMI: Type: AWS::SSM::Parameter::Value Default: /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id Description: The Amazon Machine Image ID used for the EC2 cluster Conditions: EC2: !Equals [ !Ref LaunchType, 'EC2' ] Resources: #-----------------------------------------------------------------------------# # ECS Cluster #-----------------------------------------------------------------------------# ECSCluster: Type: AWS::ECS::Cluster #-----------------------------------------------------------------------------# # Instance Autoscaling Group (EC2 Launch Type) #-----------------------------------------------------------------------------# ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup DependsOn: ECSCluster Condition: EC2 Properties: NewInstancesProtectedFromScaleIn: true VPCZoneIdentifier: # Choose private subnets if using NAT gateways - Fn::ImportValue: !Sub ${EnvironmentName}:PublicSubnetOne - Fn::ImportValue: !Sub ${EnvironmentName}:PublicSubnetTwo LaunchConfigurationName: !Ref ContainerInstances MinSize: 1 MaxSize: 3 DesiredCapacity: 1 CreationPolicy: ResourceSignal: Timeout: PT5M UpdatePolicy: # AutoScalingReplacingUpdate: # WillReplace: true AutoScalingRollingUpdate: MinSuccessfulInstancesPercent: 100 WaitOnResourceSignals: true PauseTime: PT5M SuspendProcesses: # Suspend everything except Launch and Terminate. - AddToLoadBalancer - AlarmNotification - AZRebalance - HealthCheck - ReplaceUnhealthy - ScheduledActions ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Condition: EC2 Properties: ImageId: !Ref ECSAMI SecurityGroups: - Fn::ImportValue: !Sub ${EnvironmentName}:ContainerSecurityGroup InstanceType: !Ref InstanceType IamInstanceProfile: !Ref EC2InstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash -xe echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Condition: EC2 Properties: Path: / Roles: [!Ref EC2Role] #-----------------------------------------------------------------------------# # Capacity Provider (EC2 Launch Type) #-----------------------------------------------------------------------------# ECSCapacityProvider: Type: AWS::ECS::CapacityProvider DependsOn: ECSCluster Condition: EC2 Properties: AutoScalingGroupProvider: AutoScalingGroupArn: !Ref ECSAutoScalingGroup ManagedScaling: MaximumScalingStepSize: 2 MinimumScalingStepSize: 1 Status: ENABLED TargetCapacity: 100 ManagedTerminationProtection: ENABLED ECSClusterCapProvAssoc: Type: AWS::ECS::ClusterCapacityProviderAssociations Condition: EC2 Properties: Cluster: !Ref ECSCluster CapacityProviders: - !Ref ECSCapacityProvider DefaultCapacityProviderStrategy: - CapacityProvider: !Ref ECSCapacityProvider Weight: 100 #-----------------------------------------------------------------------------# # Role for Application Autoscaling #-----------------------------------------------------------------------------# AutoscalingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [application-autoscaling.amazonaws.com] Action: [sts:AssumeRole] Path: / Policies: - PolicyName: service-autoscaling PolicyDocument: Statement: - Effect: Allow Action: - application-autoscaling:* - cloudwatch:DescribeAlarms - cloudwatch:PutMetricAlarm - ecs:DescribeServices - ecs:UpdateService Resource: '*' #-----------------------------------------------------------------------------# # Role for EC2 Hosts (EC2 Launch Type) #-----------------------------------------------------------------------------# EC2Role: Type: AWS::IAM::Role Condition: EC2 Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ec2.amazonaws.com] Action: [sts:AssumeRole] Path: / Policies: # AmazonEC2ContainerServiceforEC2Role - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: - ec2:DescribeTags - ecs:CreateCluster - ecs:DeregisterContainerInstance - ecs:DiscoverPollEndpoint - ecs:Poll - ecs:RegisterContainerInstance - ecs:StartTelemetrySession - ecs:UpdateContainerInstancesState - ecs:Submit* - ecr:GetAuthorizationToken - ecr:BatchCheckLayerAvailability - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage - logs:CreateLogStream - logs:PutLogEvents Resource: '*' #-----------------------------------------------------------------------------# # Role for ECS Tasks #-----------------------------------------------------------------------------# ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs-tasks.amazonaws.com] Action: [sts:AssumeRole] Path: / Policies: - PolicyName: AmazonECSTaskExecutionRolePolicy PolicyDocument: Statement: - Effect: Allow Action: # Allow the ECS Tasks to download images from ECR - ecr:GetAuthorizationToken - ecr:BatchCheckLayerAvailability - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage # Allow the ECS tasks to upload logs to CloudWatch - logs:CreateLogStream - logs:PutLogEvents Resource: '*' #-----------------------------------------------------------------------------# # Role for ECS #-----------------------------------------------------------------------------# ECSRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [ecs.amazonaws.com] Action: [sts:AssumeRole] Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: # Rules which allow ECS to attach network interfaces to instances # on your behalf in order for awsvpc networking mode to work right - ec2:AttachNetworkInterface - ec2:CreateNetworkInterface - ec2:CreateNetworkInterfacePermission - ec2:DeleteNetworkInterface - ec2:DeleteNetworkInterfacePermission - ec2:Describe* - ec2:DetachNetworkInterface # Rules which allow ECS to update load balancers on your behalf # with the information sabout how to send traffic to your containers - elasticloadbalancing:DeregisterInstancesFromLoadBalancer - elasticloadbalancing:DeregisterTargets - elasticloadbalancing:Describe* - elasticloadbalancing:RegisterInstancesWithLoadBalancer - elasticloadbalancing:RegisterTargets Resource: '*' Outputs: ClusterName: Description: The name of the ECS cluster Value: !Ref ECSCluster Export: Name: !Sub ${EnvironmentName}:ClusterName AutoscalingRole: Description: The ARN of the role used for autoscaling Value: !GetAtt AutoscalingRole.Arn Export: Name: !Sub ${EnvironmentName}:AutoscalingRole ECSRole: Description: The ARN of the ECS role Value: !GetAtt ECSRole.Arn Export: Name: !Sub ${EnvironmentName}:ECSRole ECSTaskExecutionRole: Description: The ARN of the ECS role Value: !GetAtt ECSTaskExecutionRole.Arn Export: Name: !Sub ${EnvironmentName}:ECSTaskExecutionRole