From 10f18ef29b77193ebaa8de651eb6e032880078a8 Mon Sep 17 00:00:00 2001 From: Paul Maddox Date: Tue, 13 Nov 2018 13:57:50 +0000 Subject: [PATCH] Updated AMIs and Auto-formatted YAML files --- infrastructure/ecs-cluster.yaml | 660 +++++++++++++------------- infrastructure/lifecyclehook.yaml | 74 +-- infrastructure/load-balancers.yaml | 111 +++-- infrastructure/security-groups.yaml | 98 ++-- infrastructure/vpc.yaml | 444 +++++++++-------- master.yaml | 169 ++++--- services/product-service/service.yaml | 236 ++++----- services/website-service/service.yaml | 452 +++++++++--------- 8 files changed, 1115 insertions(+), 1129 deletions(-) diff --git a/infrastructure/ecs-cluster.yaml b/infrastructure/ecs-cluster.yaml index 085297ff..8ba03509 100644 --- a/infrastructure/ecs-cluster.yaml +++ b/infrastructure/ecs-cluster.yaml @@ -1,349 +1,345 @@ Description: > - This template deploys an ECS cluster to the provided VPC and subnets - using an Auto Scaling Group + This template deploys an ECS cluster to the provided VPC and subnets + using an Auto Scaling Group Parameters: + EnvironmentName: + Description: An environment name that will be prefixed to resource names + Type: String - EnvironmentName: - Description: An environment name that will be prefixed to resource names - Type: String + InstanceType: + Description: Which instance type should we use to build the ECS cluster? + Type: String + Default: c4.large - InstanceType: - Description: Which instance type should we use to build the ECS cluster? - Type: String - Default: c4.large + ClusterSize: + Description: How many ECS hosts do you want to initially deploy? + Type: Number + Default: 4 - ClusterSize: - Description: How many ECS hosts do you want to initially deploy? - Type: Number - Default: 4 + VPC: + Description: Choose which VPC this ECS cluster should be deployed to + Type: AWS::EC2::VPC::Id - VPC: - Description: Choose which VPC this ECS cluster should be deployed to - Type: AWS::EC2::VPC::Id + Subnets: + Description: Choose which subnets this ECS cluster should be deployed to + Type: List - Subnets: - Description: Choose which subnets this ECS cluster should be deployed to - Type: List - - SecurityGroup: - Description: Select the Security Group to use for the ECS cluster hosts - Type: AWS::EC2::SecurityGroup::Id + SecurityGroup: + Description: Select the Security Group to use for the ECS cluster hosts + Type: AWS::EC2::SecurityGroup::Id Mappings: - - # These are the latest ECS optimized AMIs as of Feb 2018: - # - # amzn-ami-2017.09.h-amazon-ecs-optimized - # ECS agent: 1.17.1 - # Docker: 17.09.1-ce - # ecs-init: 1.17.1-1 - # - # You can find the latest available on this page of our documentation: - # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html - # (note the AMI identifier is region specific) - - AWSRegionToAMI: - us-east-2: - AMI: ami-b86a5ddd - us-east-1: - AMI: ami-a7a242da - us-west-2: - AMI: ami-92e06fea - us-west-1: - AMI: ami-9ad4dcfa - us-gov-west-1: - AMI: ami-cc3cb7ad - eu-west-3: - AMI: ami-698b3d14 - eu-west-2: - AMI: ami-f4e20693 - eu-west-1: - AMI: ami-0693ed7f - eu-central-1: - AMI: ami-0799fa68 - ap-northeast-2: - AMI: ami-a5dd70cb - ap-northeast-1: - AMI: ami-68ef940e - ap-southeast-2: - AMI: ami-ee884f8c - ap-southeast-1: - AMI: ami-0a622c76 - ca-central-1: - AMI: ami-5ac94e3e - ap-south-1: - AMI: ami-2e461a41 - sa-east-1: - AMI: ami-d44008b8 + # These are the latest ECS optimized AMIs as of Feb 2018: + # + # amzn-ami-2017.09.h-amazon-ecs-optimized + # ECS agent: 1.17.1 + # Docker: 17.09.1-ce + # ecs-init: 1.17.1-1 + # + # You can find the latest available on this page of our documentation: + # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html + # (note the AMI identifier is region specific) + + AWSRegionToAMI: + us-east-2: + AMI: ami-0a0c6574ce16ce87a + us-east-1: + AMI: ami-07eb698ce660402d2 + us-west-2: + AMI: ami-09568291a9d6c804c + us-west-1: + AMI: ami-04c22ba97a0c063c4 + eu-west-3: + AMI: ami-0a0948de946510ec0 + eu-west-2: + AMI: ami-0cb31bf24b130a0f9 + eu-west-1: + AMI: ami-066826c6a40879d75 + eu-central-1: + AMI: ami-0b9fee3a2d0596ed1 + ap-northeast-2: + AMI: ami-0b52e57bed048ca48 + ap-northeast-1: + AMI: ami-0edf19001c48838c7 + ap-southeast-2: + AMI: ami-08c26730c8ee004fa + ap-southeast-1: + AMI: ami-08d4fe232c67b81b8 + ca-central-1: + AMI: ami-055750f063052ec55 + ap-south-1: + AMI: ami-05f009513cd58ac90 + sa-east-1: + AMI: ami-0ada25501ac1375b3 + us-gov-west-1: + AMI: ami-3c39a25d Resources: - - ECSCluster: - Type: AWS::ECS::Cluster - Properties: - ClusterName: !Ref EnvironmentName - - ECSAutoScalingGroup: - DependsOn: ECSCluster - Type: AWS::AutoScaling::AutoScalingGroup - Properties: - VPCZoneIdentifier: !Ref Subnets - LaunchConfigurationName: !Ref ECSLaunchConfiguration - MinSize: !Ref ClusterSize - MaxSize: !Ref ClusterSize - DesiredCapacity: !Ref ClusterSize - Tags: - - Key: Name - Value: !Sub ${EnvironmentName} ECS host - PropagateAtLaunch: true - CreationPolicy: - ResourceSignal: - Timeout: PT15M - UpdatePolicy: - AutoScalingRollingUpdate: - MinInstancesInService: 1 - MaxBatchSize: 1 - PauseTime: PT15M - SuspendProcesses: - - HealthCheck - - ReplaceUnhealthy - - AZRebalance - - AlarmNotification - - ScheduledActions - WaitOnResourceSignals: true - - ECSLaunchConfiguration: - Type: AWS::AutoScaling::LaunchConfiguration - Properties: - ImageId: !FindInMap [AWSRegionToAMI, !Ref "AWS::Region", AMI] - InstanceType: !Ref InstanceType - SecurityGroups: - - !Ref SecurityGroup - IamInstanceProfile: !Ref ECSInstanceProfile - UserData: - "Fn::Base64": !Sub | - #!/bin/bash - yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm - yum install -y aws-cfn-bootstrap hibagent - /opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration - /opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSAutoScalingGroup - /usr/bin/enable-ec2-spot-hibernation - - Metadata: - AWS::CloudFormation::Init: - config: - packages: - yum: - awslogs: [] - - commands: - 01_add_instance_to_cluster: - command: !Sub echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config - files: - "/etc/cfn/cfn-hup.conf": - mode: 000400 - owner: root - group: root - content: !Sub | - [main] - stack=${AWS::StackId} - region=${AWS::Region} - - "/etc/cfn/hooks.d/cfn-auto-reloader.conf": - content: !Sub | - [cfn-auto-reloader-hook] - triggers=post.update - path=Resources.ECSLaunchConfiguration.Metadata.AWS::CloudFormation::Init - action=/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration - - "/etc/awslogs/awscli.conf": - content: !Sub | - [plugins] - cwlogs = cwlogs - [default] - region = ${AWS::Region} - - "/etc/awslogs/awslogs.conf": - content: !Sub | - [general] - state_file = /var/lib/awslogs/agent-state - - [/var/log/dmesg] - file = /var/log/dmesg - log_group_name = ${ECSCluster}-/var/log/dmesg - log_stream_name = ${ECSCluster} - - [/var/log/messages] - file = /var/log/messages - log_group_name = ${ECSCluster}-/var/log/messages - log_stream_name = ${ECSCluster} - datetime_format = %b %d %H:%M:%S - - [/var/log/docker] - file = /var/log/docker - log_group_name = ${ECSCluster}-/var/log/docker - log_stream_name = ${ECSCluster} - datetime_format = %Y-%m-%dT%H:%M:%S.%f - - [/var/log/ecs/ecs-init.log] - file = /var/log/ecs/ecs-init.log.* - log_group_name = ${ECSCluster}-/var/log/ecs/ecs-init.log - log_stream_name = ${ECSCluster} - datetime_format = %Y-%m-%dT%H:%M:%SZ - - [/var/log/ecs/ecs-agent.log] - file = /var/log/ecs/ecs-agent.log.* - log_group_name = ${ECSCluster}-/var/log/ecs/ecs-agent.log - log_stream_name = ${ECSCluster} - datetime_format = %Y-%m-%dT%H:%M:%SZ - - [/var/log/ecs/audit.log] - file = /var/log/ecs/audit.log.* - log_group_name = ${ECSCluster}-/var/log/ecs/audit.log - log_stream_name = ${ECSCluster} - datetime_format = %Y-%m-%dT%H:%M:%SZ - - services: - sysvinit: - cfn-hup: - enabled: true - ensureRunning: true - files: - - /etc/cfn/cfn-hup.conf - - /etc/cfn/hooks.d/cfn-auto-reloader.conf - awslogs: - enabled: true - ensureRunning: true - files: - - /etc/awslogs/awslogs.conf - - /etc/awslogs/awscli.conf - - # This IAM Role is attached to all of the ECS hosts. It is based on the default role - # published here: - # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html - # - # You can add other IAM policy statements here to allow access from your ECS hosts - # to other AWS services. Please note that this role will be used by ALL containers - # running on the ECS host. - - ECSRole: - Type: AWS::IAM::Role - Properties: - Path: / - RoleName: !Sub ${EnvironmentName}-ECSRole-${AWS::Region} - AssumeRolePolicyDocument: | - { - "Statement": [{ - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "ec2.amazonaws.com" - } - }] + ECSCluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: !Ref EnvironmentName + + ECSAutoScalingGroup: + DependsOn: ECSCluster + Type: AWS::AutoScaling::AutoScalingGroup + Properties: + VPCZoneIdentifier: !Ref Subnets + LaunchConfigurationName: !Ref ECSLaunchConfiguration + MinSize: !Ref ClusterSize + MaxSize: !Ref ClusterSize + DesiredCapacity: !Ref ClusterSize + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} ECS host + PropagateAtLaunch: true + CreationPolicy: + ResourceSignal: + Timeout: PT15M + UpdatePolicy: + AutoScalingRollingUpdate: + MinInstancesInService: 1 + MaxBatchSize: 1 + PauseTime: PT15M + SuspendProcesses: + - HealthCheck + - ReplaceUnhealthy + - AZRebalance + - AlarmNotification + - ScheduledActions + WaitOnResourceSignals: true + + ECSLaunchConfiguration: + Type: AWS::AutoScaling::LaunchConfiguration + Properties: + ImageId: !FindInMap [AWSRegionToAMI, !Ref "AWS::Region", AMI] + InstanceType: !Ref InstanceType + SecurityGroups: + - !Ref SecurityGroup + IamInstanceProfile: !Ref ECSInstanceProfile + UserData: + "Fn::Base64": !Sub | + #!/bin/bash + yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm + yum install -y aws-cfn-bootstrap hibagent + /opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration + /opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSAutoScalingGroup + /usr/bin/enable-ec2-spot-hibernation + + Metadata: + AWS::CloudFormation::Init: + config: + packages: + yum: + awslogs: [] + + commands: + 01_add_instance_to_cluster: + command: !Sub echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config + files: + "/etc/cfn/cfn-hup.conf": + mode: 000400 + owner: root + group: root + content: !Sub | + [main] + stack=${AWS::StackId} + region=${AWS::Region} + + "/etc/cfn/hooks.d/cfn-auto-reloader.conf": + content: !Sub | + [cfn-auto-reloader-hook] + triggers=post.update + path=Resources.ECSLaunchConfiguration.Metadata.AWS::CloudFormation::Init + action=/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource ECSLaunchConfiguration + + "/etc/awslogs/awscli.conf": + content: !Sub | + [plugins] + cwlogs = cwlogs + [default] + region = ${AWS::Region} + + "/etc/awslogs/awslogs.conf": + content: !Sub | + [general] + state_file = /var/lib/awslogs/agent-state + + [/var/log/dmesg] + file = /var/log/dmesg + log_group_name = ${ECSCluster}-/var/log/dmesg + log_stream_name = ${ECSCluster} + + [/var/log/messages] + file = /var/log/messages + log_group_name = ${ECSCluster}-/var/log/messages + log_stream_name = ${ECSCluster} + datetime_format = %b %d %H:%M:%S + + [/var/log/docker] + file = /var/log/docker + log_group_name = ${ECSCluster}-/var/log/docker + log_stream_name = ${ECSCluster} + datetime_format = %Y-%m-%dT%H:%M:%S.%f + + [/var/log/ecs/ecs-init.log] + file = /var/log/ecs/ecs-init.log.* + log_group_name = ${ECSCluster}-/var/log/ecs/ecs-init.log + log_stream_name = ${ECSCluster} + datetime_format = %Y-%m-%dT%H:%M:%SZ + + [/var/log/ecs/ecs-agent.log] + file = /var/log/ecs/ecs-agent.log.* + log_group_name = ${ECSCluster}-/var/log/ecs/ecs-agent.log + log_stream_name = ${ECSCluster} + datetime_format = %Y-%m-%dT%H:%M:%SZ + + [/var/log/ecs/audit.log] + file = /var/log/ecs/audit.log.* + log_group_name = ${ECSCluster}-/var/log/ecs/audit.log + log_stream_name = ${ECSCluster} + datetime_format = %Y-%m-%dT%H:%M:%SZ + + services: + sysvinit: + cfn-hup: + enabled: true + ensureRunning: true + files: + - /etc/cfn/cfn-hup.conf + - /etc/cfn/hooks.d/cfn-auto-reloader.conf + awslogs: + enabled: true + ensureRunning: true + files: + - /etc/awslogs/awslogs.conf + - /etc/awslogs/awscli.conf + + # This IAM Role is attached to all of the ECS hosts. It is based on the default role + # published here: + # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html + # + # You can add other IAM policy statements here to allow access from your ECS hosts + # to other AWS services. Please note that this role will be used by ALL containers + # running on the ECS host. + + ECSRole: + Type: AWS::IAM::Role + Properties: + Path: / + RoleName: !Sub ${EnvironmentName}-ECSRole-${AWS::Region} + AssumeRolePolicyDocument: | + { + "Statement": [{ + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" } - Policies: - - PolicyName: ecs-service - PolicyDocument: | - { - "Statement": [{ - "Effect": "Allow", - "Action": [ - "ecs:CreateCluster", - "ecs:DeregisterContainerInstance", - "ecs:DiscoverPollEndpoint", - "ecs:Poll", - "ecs:RegisterContainerInstance", - "ecs:StartTelemetrySession", - "ecs:Submit*", - "logs:CreateLogStream", - "logs:PutLogEvents", - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:GetDownloadUrlForLayer", - "ecr:GetAuthorizationToken", - "ssm:DescribeAssociation", - "ssm:GetDeployablePatchSnapshotForInstance", - "ssm:GetDocument", - "ssm:GetManifest", - "ssm:GetParameters", - "ssm:ListAssociations", - "ssm:ListInstanceAssociations", - "ssm:PutInventory", - "ssm:PutComplianceItems", - "ssm:PutConfigurePackageResult", - "ssm:UpdateAssociationStatus", - "ssm:UpdateInstanceAssociationStatus", - "ssm:UpdateInstanceInformation", - "ec2messages:AcknowledgeMessage", - "ec2messages:DeleteMessage", - "ec2messages:FailMessage", - "ec2messages:GetEndpoint", - "ec2messages:GetMessages", - "ec2messages:SendReply", - "cloudwatch:PutMetricData", - "ec2:DescribeInstanceStatus", - "ds:CreateComputer", - "ds:DescribeDirectories", - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - "s3:PutObject", - "s3:GetObject", - "s3:AbortMultipartUpload", - "s3:ListMultipartUploadParts", - "s3:ListBucket", - "s3:ListBucketMultipartUploads" - ], - "Resource": "*" - }] - } - - ECSInstanceProfile: - Type: AWS::IAM::InstanceProfile - Properties: - Path: / - Roles: - - !Ref ECSRole - - ECSServiceAutoScalingRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - Action: - - 'sts:AssumeRole' - Effect: Allow - Principal: - Service: - - application-autoscaling.amazonaws.com - Path: / - Policies: - - PolicyName: ecs-service-autoscaling - PolicyDocument: - Statement: - Effect: Allow - Action: - - application-autoscaling:* - - cloudwatch:DescribeAlarms - - cloudwatch:PutMetricAlarm - - ecs:DescribeServices - - ecs:UpdateService - Resource: "*" + }] + } + Policies: + - PolicyName: ecs-service + PolicyDocument: | + { + "Statement": [{ + "Effect": "Allow", + "Action": [ + "ecs:CreateCluster", + "ecs:DeregisterContainerInstance", + "ecs:DiscoverPollEndpoint", + "ecs:Poll", + "ecs:RegisterContainerInstance", + "ecs:StartTelemetrySession", + "ecs:Submit*", + "logs:CreateLogStream", + "logs:PutLogEvents", + "ecr:BatchCheckLayerAvailability", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", + "ecr:GetAuthorizationToken", + "ssm:DescribeAssociation", + "ssm:GetDeployablePatchSnapshotForInstance", + "ssm:GetDocument", + "ssm:GetManifest", + "ssm:GetParameters", + "ssm:ListAssociations", + "ssm:ListInstanceAssociations", + "ssm:PutInventory", + "ssm:PutComplianceItems", + "ssm:PutConfigurePackageResult", + "ssm:UpdateAssociationStatus", + "ssm:UpdateInstanceAssociationStatus", + "ssm:UpdateInstanceInformation", + "ec2messages:AcknowledgeMessage", + "ec2messages:DeleteMessage", + "ec2messages:FailMessage", + "ec2messages:GetEndpoint", + "ec2messages:GetMessages", + "ec2messages:SendReply", + "cloudwatch:PutMetricData", + "ec2:DescribeInstanceStatus", + "ds:CreateComputer", + "ds:DescribeDirectories", + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", + "s3:PutObject", + "s3:GetObject", + "s3:AbortMultipartUpload", + "s3:ListMultipartUploadParts", + "s3:ListBucket", + "s3:ListBucketMultipartUploads" + ], + "Resource": "*" + }] + } + + ECSInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Path: / + Roles: + - !Ref ECSRole + + ECSServiceAutoScalingRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + Action: + - "sts:AssumeRole" + Effect: Allow + Principal: + Service: + - application-autoscaling.amazonaws.com + Path: / + Policies: + - PolicyName: ecs-service-autoscaling + PolicyDocument: + Statement: + Effect: Allow + Action: + - application-autoscaling:* + - cloudwatch:DescribeAlarms + - cloudwatch:PutMetricAlarm + - ecs:DescribeServices + - ecs:UpdateService + Resource: "*" Outputs: + Cluster: + Description: A reference to the ECS cluster + Value: !Ref ECSCluster - Cluster: - Description: A reference to the ECS cluster - Value: !Ref ECSCluster - - ECSServiceAutoScalingRole: - Description: A reference to ECS service auto scaling role - Value: !GetAtt ECSServiceAutoScalingRole.Arn + ECSServiceAutoScalingRole: + Description: A reference to ECS service auto scaling role + Value: !GetAtt ECSServiceAutoScalingRole.Arn - ECSAutoScalingGroupName: - Description: A reference to ECS AutoScaling Group Name - Value: !Ref ECSAutoScalingGroup + ECSAutoScalingGroupName: + Description: A reference to ECS AutoScaling Group Name + Value: !Ref ECSAutoScalingGroup diff --git a/infrastructure/lifecyclehook.yaml b/infrastructure/lifecyclehook.yaml index c7a3d316..5aff4612 100644 --- a/infrastructure/lifecyclehook.yaml +++ b/infrastructure/lifecyclehook.yaml @@ -1,5 +1,5 @@ Description: > - This template deploys a Lambda Function and Auto Scaling Lifecycle Hook to drain Tasks from your Container Instances when an Instance is selected for Termination in your Auto Scaling Group. + This template deploys a Lambda Function and Auto Scaling Lifecycle Hook to drain Tasks from your Container Instances when an Instance is selected for Termination in your Auto Scaling Group. Parameters: Cluster: Type: String @@ -9,28 +9,28 @@ Parameters: Description: Name of Auto Scaling Group Resources: NotificationTopic: - Type: 'AWS::SNS::Topic' + Type: "AWS::SNS::Topic" Properties: Subscription: - - Endpoint: !GetAtt + - Endpoint: !GetAtt - LifecycleHandlerFunction - Arn Protocol: lambda DependsOn: LifecycleHandlerFunction InstanceTerminatingHook: - Type: 'AWS::AutoScaling::LifecycleHook' + Type: "AWS::AutoScaling::LifecycleHook" Properties: AutoScalingGroupName: !Ref ECSAutoScalingGroupName DefaultResult: ABANDON - HeartbeatTimeout: '900' - LifecycleTransition: 'autoscaling:EC2_INSTANCE_TERMINATING' + HeartbeatTimeout: "900" + LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING" NotificationTargetARN: !Ref NotificationTopic - RoleARN: !GetAtt + RoleARN: !GetAtt - AutoscalingNotificationRole - Arn DependsOn: NotificationTopic AutoscalingNotificationRole: - Type: 'AWS::IAM::Role' + Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 @@ -40,11 +40,11 @@ Resources: Service: - autoscaling.amazonaws.com Action: - - 'sts:AssumeRole' + - "sts:AssumeRole" ManagedPolicyArns: - - 'arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole' + - "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole" LambdaExecutionRole: - Type: 'AWS::IAM::Role' + Type: "AWS::IAM::Role" Properties: Policies: - PolicyName: lambda-inline @@ -53,24 +53,24 @@ Resources: Statement: - Effect: Allow Action: - - 'autoscaling:CompleteLifecycleAction' - - 'logs:CreateLogGroup' - - 'logs:CreateLogStream' - - 'logs:PutLogEvents' - - 'ec2:DescribeInstances' - - 'ec2:DescribeInstanceAttribute' - - 'ec2:DescribeInstanceStatus' - - 'ec2:DescribeHosts' - - 'ecs:ListContainerInstances' - - 'ecs:SubmitContainerStateChange' - - 'ecs:SubmitTaskStateChange' - - 'ecs:DescribeContainerInstances' - - 'ecs:UpdateContainerInstancesState' - - 'ecs:ListTasks' - - 'ecs:DescribeTasks' - - 'sns:Publish' - - 'sns:ListSubscriptions' - Resource: '*' + - "autoscaling:CompleteLifecycleAction" + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + - "ec2:DescribeInstances" + - "ec2:DescribeInstanceAttribute" + - "ec2:DescribeInstanceStatus" + - "ec2:DescribeHosts" + - "ecs:ListContainerInstances" + - "ecs:SubmitContainerStateChange" + - "ecs:SubmitTaskStateChange" + - "ecs:DescribeContainerInstances" + - "ecs:UpdateContainerInstancesState" + - "ecs:ListTasks" + - "ecs:DescribeTasks" + - "sns:Publish" + - "sns:ListSubscriptions" + Resource: "*" AssumeRolePolicyDocument: Version: 2012-10-17 Statement: @@ -79,25 +79,25 @@ Resources: Service: - lambda.amazonaws.com Action: - - 'sts:AssumeRole' + - "sts:AssumeRole" ManagedPolicyArns: - - 'arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole' + - "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole" LambdaInvokePermission: - Type: 'AWS::Lambda::Permission' + Type: "AWS::Lambda::Permission" Properties: FunctionName: !Ref LifecycleHandlerFunction - Action: 'lambda:InvokeFunction' + Action: "lambda:InvokeFunction" Principal: sns.amazonaws.com SourceArn: !Ref NotificationTopic LifecycleHandlerFunction: - Type: 'AWS::Lambda::Function' + Type: "AWS::Lambda::Function" Properties: Environment: Variables: CLUSTER: !Ref Cluster Code: - ZipFile: !Join - - '' + ZipFile: !Join + - "" - - | import boto3,json,os,time ec2Client = boto3.client('ec2') @@ -138,7 +138,7 @@ Resources: time.sleep(5) publishSNSMessage(snsMessage,snsTopicArn) Handler: index.lambda_handler - Role: !GetAtt + Role: !GetAtt - LambdaExecutionRole - Arn Runtime: python3.6 diff --git a/infrastructure/load-balancers.yaml b/infrastructure/load-balancers.yaml index 82a8bc1a..d0750282 100644 --- a/infrastructure/load-balancers.yaml +++ b/infrastructure/load-balancers.yaml @@ -1,71 +1,66 @@ Description: > - This template deploys an Application Load Balancer that exposes our various ECS services. - We create them in a seperate nested template, so it can be referenced by all of the other nested templates. + This template deploys an Application Load Balancer that exposes our various ECS services. + We create them in a seperate nested template, so it can be referenced by all of the other nested templates. Parameters: + EnvironmentName: + Description: An environment name that will be prefixed to resource names + Type: String - EnvironmentName: - Description: An environment name that will be prefixed to resource names - Type: String + VPC: + Type: AWS::EC2::VPC::Id + Description: Choose which VPC the Application Load Balancer should be deployed to - VPC: - Type: AWS::EC2::VPC::Id - Description: Choose which VPC the Application Load Balancer should be deployed to + Subnets: + Description: Choose which subnets the Application Load Balancer should be deployed to + Type: List - Subnets: - Description: Choose which subnets the Application Load Balancer should be deployed to - Type: List - - SecurityGroup: - Description: Select the Security Group to apply to the Application Load Balancer - Type: AWS::EC2::SecurityGroup::Id + SecurityGroup: + Description: Select the Security Group to apply to the Application Load Balancer + Type: AWS::EC2::SecurityGroup::Id Resources: + LoadBalancer: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Name: !Ref EnvironmentName + Subnets: !Ref Subnets + SecurityGroups: + - !Ref SecurityGroup + Tags: + - Key: Name + Value: !Ref EnvironmentName - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Ref EnvironmentName - Subnets: !Ref Subnets - SecurityGroups: - - !Ref SecurityGroup - Tags: - - Key: Name - Value: !Ref EnvironmentName - - LoadBalancerListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref LoadBalancer - Port: 80 - Protocol: HTTP - DefaultActions: - - Type: forward - TargetGroupArn: !Ref DefaultTargetGroup - - # We define a default target group here, as this is a mandatory Parameters - # when creating an Application Load Balancer Listener. This is not used, instead - # a target group is created per-service in each service template (../services/*) - DefaultTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - Name: !Sub ${EnvironmentName}-default - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - -Outputs: + LoadBalancerListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + LoadBalancerArn: !Ref LoadBalancer + Port: 80 + Protocol: HTTP + DefaultActions: + - Type: forward + TargetGroupArn: !Ref DefaultTargetGroup - LoadBalancer: - Description: A reference to the Application Load Balancer - Value: !Ref LoadBalancer + # We define a default target group here, as this is a mandatory Parameters + # when creating an Application Load Balancer Listener. This is not used, instead + # a target group is created per-service in each service template (../services/*) + DefaultTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + Name: !Sub ${EnvironmentName}-default + VpcId: !Ref VPC + Port: 80 + Protocol: HTTP - LoadBalancerUrl: - Description: The URL of the ALB - Value: !GetAtt LoadBalancer.DNSName +Outputs: + LoadBalancer: + Description: A reference to the Application Load Balancer + Value: !Ref LoadBalancer - Listener: - Description: A reference to a port 80 listener - Value: !Ref LoadBalancerListener + LoadBalancerUrl: + Description: The URL of the ALB + Value: !GetAtt LoadBalancer.DNSName - + Listener: + Description: A reference to a port 80 listener + Value: !Ref LoadBalancerListener diff --git a/infrastructure/security-groups.yaml b/infrastructure/security-groups.yaml index c357ad94..429eb612 100644 --- a/infrastructure/security-groups.yaml +++ b/infrastructure/security-groups.yaml @@ -1,59 +1,55 @@ Description: > - This template contains the security groups required by our entire stack. - We create them in a seperate nested template, so they can be referenced - by all of the other nested templates. + This template contains the security groups required by our entire stack. + We create them in a seperate nested template, so they can be referenced + by all of the other nested templates. Parameters: - - EnvironmentName: - Description: An environment name that will be prefixed to resource names - Type: String - - VPC: - Type: AWS::EC2::VPC::Id - Description: Choose which VPC the security groups should be deployed to + EnvironmentName: + Description: An environment name that will be prefixed to resource names + Type: String -Resources: - - # This security group defines who/where is allowed to access the ECS hosts directly. - # By default we're just allowing access from the load balancer. If you want to SSH - # into the hosts, or expose non-load balanced services you can open their ports here. - ECSHostSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref VPC - GroupDescription: Access to the ECS hosts and the tasks/containers that run on them - SecurityGroupIngress: - # Only allow inbound access to ECS from the ELB - - SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup - IpProtocol: -1 - Tags: - - Key: Name - Value: !Sub ${EnvironmentName}-ECS-Hosts + VPC: + Type: AWS::EC2::VPC::Id + Description: Choose which VPC the security groups should be deployed to - # This security group defines who/where is allowed to access the Application Load Balancer. - # By default, we've opened this up to the public internet (0.0.0.0/0) but can you restrict - # it further if you want. - LoadBalancerSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - VpcId: !Ref VPC - GroupDescription: Access to the load balancer that sits in front of ECS - SecurityGroupIngress: - # Allow access from anywhere to our ECS services - - CidrIp: 0.0.0.0/0 - IpProtocol: -1 - Tags: - - Key: Name - Value: !Sub ${EnvironmentName}-LoadBalancers +Resources: + # This security group defines who/where is allowed to access the ECS hosts directly. + # By default we're just allowing access from the load balancer. If you want to SSH + # into the hosts, or expose non-load balanced services you can open their ports here. + ECSHostSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + VpcId: !Ref VPC + GroupDescription: Access to the ECS hosts and the tasks/containers that run on them + SecurityGroupIngress: + # Only allow inbound access to ECS from the ELB + - SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup + IpProtocol: -1 + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-ECS-Hosts + + # This security group defines who/where is allowed to access the Application Load Balancer. + # By default, we've opened this up to the public internet (0.0.0.0/0) but can you restrict + # it further if you want. + LoadBalancerSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + VpcId: !Ref VPC + GroupDescription: Access to the load balancer that sits in front of ECS + SecurityGroupIngress: + # Allow access from anywhere to our ECS services + - CidrIp: 0.0.0.0/0 + IpProtocol: -1 + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-LoadBalancers Outputs: + ECSHostSecurityGroup: + Description: A reference to the security group for ECS hosts + Value: !Ref ECSHostSecurityGroup - ECSHostSecurityGroup: - Description: A reference to the security group for ECS hosts - Value: !Ref ECSHostSecurityGroup - - LoadBalancerSecurityGroup: - Description: A reference to the security group for load balancers - Value: !Ref LoadBalancerSecurityGroup - + LoadBalancerSecurityGroup: + Description: A reference to the security group for load balancers + Value: !Ref LoadBalancerSecurityGroup diff --git a/infrastructure/vpc.yaml b/infrastructure/vpc.yaml index fa07354d..e43cb81c 100644 --- a/infrastructure/vpc.yaml +++ b/infrastructure/vpc.yaml @@ -1,229 +1,225 @@ Description: > - This template deploys a VPC, with a pair of public and private subnets spread - across two Availabilty Zones. It deploys an Internet Gateway, with a default - route on the public subnets. It deploys a pair of NAT Gateways (one in each AZ), - and default routes for them in the private subnets. + This template deploys a VPC, with a pair of public and private subnets spread + across two Availabilty Zones. It deploys an Internet Gateway, with a default + route on the public subnets. It deploys a pair of NAT Gateways (one in each AZ), + and default routes for them in the private subnets. Parameters: - - EnvironmentName: - Description: An environment name that will be prefixed to resource names - Type: String - - VpcCIDR: - Description: Please enter the IP range (CIDR notation) for this VPC - Type: String - Default: 10.192.0.0/16 - - PublicSubnet1CIDR: - Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone - Type: String - Default: 10.192.10.0/24 - - PublicSubnet2CIDR: - Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone - Type: String - Default: 10.192.11.0/24 - - PrivateSubnet1CIDR: - Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone - Type: String - Default: 10.192.20.0/24 - - PrivateSubnet2CIDR: - Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone - Type: String - Default: 10.192.21.0/24 + EnvironmentName: + Description: An environment name that will be prefixed to resource names + Type: String + + VpcCIDR: + Description: Please enter the IP range (CIDR notation) for this VPC + Type: String + Default: 10.192.0.0/16 + + PublicSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone + Type: String + Default: 10.192.10.0/24 + + PublicSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone + Type: String + Default: 10.192.11.0/24 + + PrivateSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone + Type: String + Default: 10.192.20.0/24 + + PrivateSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone + Type: String + Default: 10.192.21.0/24 Resources: - - VPC: - Type: AWS::EC2::VPC - Properties: - CidrBlock: !Ref VpcCIDR - EnableDnsHostnames: true - Tags: - - Key: Name - Value: !Ref EnvironmentName - - InternetGateway: - Type: AWS::EC2::InternetGateway - Properties: - Tags: - - Key: Name - Value: !Ref EnvironmentName - - 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 - -Outputs: - - VPC: - Description: A reference to the created VPC - Value: !Ref VPC - - PublicSubnets: - Description: A list of the public subnets - Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]] - - PrivateSubnets: - Description: A list of the private subnets - Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]] - - PublicSubnet1: - Description: A reference to the public subnet in the 1st Availability Zone - Value: !Ref PublicSubnet1 - - PublicSubnet2: - Description: A reference to the public subnet in the 2nd Availability Zone - Value: !Ref PublicSubnet2 - - PrivateSubnet1: - Description: A reference to the private subnet in the 1st Availability Zone - Value: !Ref PrivateSubnet1 - - PrivateSubnet2: - Description: A reference to the private subnet in the 2nd Availability Zone - Value: !Ref PrivateSubnet2 + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsHostnames: true + Tags: + - Key: Name + Value: !Ref EnvironmentName + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Ref EnvironmentName + + 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 ${EnvironmentName} 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 + +Outputs: + VPC: + Description: A reference to the created VPC + Value: !Ref VPC + + PublicSubnets: + Description: A list of the public subnets + Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]] + + PrivateSubnets: + Description: A list of the private subnets + Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]] + + PublicSubnet1: + Description: A reference to the public subnet in the 1st Availability Zone + Value: !Ref PublicSubnet1 + + PublicSubnet2: + Description: A reference to the public subnet in the 2nd Availability Zone + Value: !Ref PublicSubnet2 + + PrivateSubnet1: + Description: A reference to the private subnet in the 1st Availability Zone + Value: !Ref PrivateSubnet1 + + PrivateSubnet2: + Description: A reference to the private subnet in the 2nd Availability Zone + Value: !Ref PrivateSubnet2 diff --git a/master.yaml b/master.yaml index 349293ad..51b47a1e 100644 --- a/master.yaml +++ b/master.yaml @@ -1,101 +1,100 @@ Description: > - This template deploys a VPC, with a pair of public and private subnets spread - across two Availabilty Zones. It deploys an Internet Gateway, with a default - route on the public subnets. It deploys a pair of NAT Gateways (one in each AZ), - and default routes for them in the private subnets. + This template deploys a VPC, with a pair of public and private subnets spread + across two Availabilty Zones. It deploys an Internet Gateway, with a default + route on the public subnets. It deploys a pair of NAT Gateways (one in each AZ), + and default routes for them in the private subnets. - It then deploys a highly available ECS cluster using an AutoScaling Group, with - ECS hosts distributed across multiple Availability Zones. + It then deploys a highly available ECS cluster using an AutoScaling Group, with + ECS hosts distributed across multiple Availability Zones. - Finally, it deploys a pair of example ECS services from containers published in - Amazon EC2 Container Registry (Amazon ECR). + Finally, it deploys a pair of example ECS services from containers published in + Amazon EC2 Container Registry (Amazon ECR). - Last Modified: 22nd September 2016 - Author: Paul Maddox + Last Modified: 22nd September 2016 + Author: Paul Maddox Resources: + VPC: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/vpc.yaml + Parameters: + EnvironmentName: !Ref AWS::StackName + VpcCIDR: 10.180.0.0/16 + PublicSubnet1CIDR: 10.180.8.0/21 + PublicSubnet2CIDR: 10.180.16.0/21 + PrivateSubnet1CIDR: 10.180.24.0/21 + PrivateSubnet2CIDR: 10.180.32.0/21 - VPC: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/vpc.yaml - Parameters: - EnvironmentName: !Ref AWS::StackName - VpcCIDR: 10.180.0.0/16 - PublicSubnet1CIDR: 10.180.8.0/21 - PublicSubnet2CIDR: 10.180.16.0/21 - PrivateSubnet1CIDR: 10.180.24.0/21 - PrivateSubnet2CIDR: 10.180.32.0/21 + SecurityGroups: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/security-groups.yaml + Parameters: + EnvironmentName: !Ref AWS::StackName + VPC: !GetAtt VPC.Outputs.VPC - SecurityGroups: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/security-groups.yaml - Parameters: - EnvironmentName: !Ref AWS::StackName - VPC: !GetAtt VPC.Outputs.VPC + ALB: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/load-balancers.yaml + Parameters: + EnvironmentName: !Ref AWS::StackName + VPC: !GetAtt VPC.Outputs.VPC + Subnets: !GetAtt VPC.Outputs.PublicSubnets + SecurityGroup: !GetAtt SecurityGroups.Outputs.LoadBalancerSecurityGroup - ALB: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/load-balancers.yaml - Parameters: - EnvironmentName: !Ref AWS::StackName - VPC: !GetAtt VPC.Outputs.VPC - Subnets: !GetAtt VPC.Outputs.PublicSubnets - SecurityGroup: !GetAtt SecurityGroups.Outputs.LoadBalancerSecurityGroup + ECS: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/ecs-cluster.yaml + Parameters: + EnvironmentName: !Ref AWS::StackName + InstanceType: t2.large + ClusterSize: 4 + VPC: !GetAtt VPC.Outputs.VPC + SecurityGroup: !GetAtt SecurityGroups.Outputs.ECSHostSecurityGroup + Subnets: !GetAtt VPC.Outputs.PrivateSubnets - ECS: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/ecs-cluster.yaml - Parameters: - EnvironmentName: !Ref AWS::StackName - InstanceType: t2.large - ClusterSize: 4 - VPC: !GetAtt VPC.Outputs.VPC - SecurityGroup: !GetAtt SecurityGroups.Outputs.ECSHostSecurityGroup - Subnets: !GetAtt VPC.Outputs.PrivateSubnets + ProductService: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/services/product-service/service.yaml + Parameters: + VPC: !GetAtt VPC.Outputs.VPC + Cluster: !GetAtt ECS.Outputs.Cluster + DesiredCount: 2 + Listener: !GetAtt ALB.Outputs.Listener + Path: /products - ProductService: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/services/product-service/service.yaml - Parameters: - VPC: !GetAtt VPC.Outputs.VPC - Cluster: !GetAtt ECS.Outputs.Cluster - DesiredCount: 2 - Listener: !GetAtt ALB.Outputs.Listener - Path: /products + WebsiteService: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/services/website-service/service.yaml + Parameters: + VPC: !GetAtt VPC.Outputs.VPC + Cluster: !GetAtt ECS.Outputs.Cluster + DesiredCount: 2 + ProductServiceUrl: + !Join ["/", [!GetAtt ALB.Outputs.LoadBalancerUrl, "products"]] + Listener: !GetAtt ALB.Outputs.Listener + Path: / + ECSServiceAutoScalingRoleARN: !GetAtt ECS.Outputs.ECSServiceAutoScalingRole - WebsiteService: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/services/website-service/service.yaml - Parameters: - VPC: !GetAtt VPC.Outputs.VPC - Cluster: !GetAtt ECS.Outputs.Cluster - DesiredCount: 2 - ProductServiceUrl: !Join [ "/", [ !GetAtt ALB.Outputs.LoadBalancerUrl, "products" ]] - Listener: !GetAtt ALB.Outputs.Listener - Path: / - ECSServiceAutoScalingRoleARN: !GetAtt ECS.Outputs.ECSServiceAutoScalingRole - - LifecycleHook: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/lifecyclehook.yaml - Parameters: - Cluster: !GetAtt ECS.Outputs.Cluster - ECSAutoScalingGroupName: !GetAtt ECS.Outputs.ECSAutoScalingGroupName + LifecycleHook: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/lifecyclehook.yaml + Parameters: + Cluster: !GetAtt ECS.Outputs.Cluster + ECSAutoScalingGroupName: !GetAtt ECS.Outputs.ECSAutoScalingGroupName Outputs: + ProductServiceUrl: + Description: The URL endpoint for the product service + Value: !Join ["/", [!GetAtt ALB.Outputs.LoadBalancerUrl, "products"]] - ProductServiceUrl: - Description: The URL endpoint for the product service - Value: !Join [ "/", [ !GetAtt ALB.Outputs.LoadBalancerUrl, "products" ]] - - WebsiteServiceUrl: - Description: The URL endpoint for the website service - Value: !Join ["", [ !GetAtt ALB.Outputs.LoadBalancerUrl, "/" ]] + WebsiteServiceUrl: + Description: The URL endpoint for the website service + Value: !Join ["", [!GetAtt ALB.Outputs.LoadBalancerUrl, "/"]] diff --git a/services/product-service/service.yaml b/services/product-service/service.yaml index 6afc9275..3c002243 100644 --- a/services/product-service/service.yaml +++ b/services/product-service/service.yaml @@ -1,129 +1,131 @@ Description: > - This is an example of a long running ECS service that serves a JSON API of products. + This is an example of a long running ECS service that serves a JSON API of products. -Parameters: +Parameters: + VPC: + Description: The VPC that the ECS cluster is deployed to + Type: AWS::EC2::VPC::Id - VPC: - Description: The VPC that the ECS cluster is deployed to - Type: AWS::EC2::VPC::Id - - Cluster: - Description: Please provide the ECS Cluster ID that this service should run on - Type: String + Cluster: + Description: Please provide the ECS Cluster ID that this service should run on + Type: String - DesiredCount: - Description: How many instances of this task should we run across our cluster? - Type: Number - Default: 2 + DesiredCount: + Description: How many instances of this task should we run across our cluster? + Type: Number + Default: 2 - Listener: - Description: The Application Load Balancer listener to register with - Type: String + Listener: + Description: The Application Load Balancer listener to register with + Type: String - Path: - Description: The path to register with the Application Load Balancer - Type: String - Default: /products + Path: + Description: The path to register with the Application Load Balancer + Type: String + Default: /products Resources: + Service: + Type: AWS::ECS::Service + DependsOn: ListenerRule + Properties: + Cluster: !Ref Cluster + Role: !Ref ServiceRole + DesiredCount: !Ref DesiredCount + TaskDefinition: !Ref TaskDefinition + LoadBalancers: + - ContainerName: "product-service" + ContainerPort: 8001 + TargetGroupArn: !Ref TargetGroup - Service: - Type: AWS::ECS::Service - DependsOn: ListenerRule - Properties: - Cluster: !Ref Cluster - Role: !Ref ServiceRole - DesiredCount: !Ref DesiredCount - TaskDefinition: !Ref TaskDefinition - LoadBalancers: - - ContainerName: "product-service" - ContainerPort: 8001 - TargetGroupArn: !Ref TargetGroup + TaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: product-service + ContainerDefinitions: + - Name: product-service + Essential: true + Image: 275396840892.dkr.ecr.us-east-1.amazonaws.com/ecs-refarch-cloudformation/product-service:1.0.0 + Memory: 128 + PortMappings: + - ContainerPort: 8001 + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref CloudWatchLogsGroup + awslogs-region: !Ref AWS::Region - TaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: product-service - ContainerDefinitions: - - Name: product-service - Essential: true - Image: 275396840892.dkr.ecr.us-east-1.amazonaws.com/ecs-refarch-cloudformation/product-service:1.0.0 - Memory: 128 - PortMappings: - - ContainerPort: 8001 - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref CloudWatchLogsGroup - awslogs-region: !Ref AWS::Region - - CloudWatchLogsGroup: - Type: AWS::Logs::LogGroup - Properties: - LogGroupName: !Ref AWS::StackName - RetentionInDays: 365 + CloudWatchLogsGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Ref AWS::StackName + RetentionInDays: 365 - TargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - Matcher: - HttpCode: 200-299 - HealthCheckIntervalSeconds: 10 - HealthCheckPath: /products - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - - ListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: !Ref Listener - Priority: 2 - Conditions: - - Field: path-pattern - Values: - - !Ref Path - Actions: - - TargetGroupArn: !Ref TargetGroup - Type: forward + TargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: !Ref VPC + Port: 80 + Protocol: HTTP + Matcher: + HttpCode: 200-299 + HealthCheckIntervalSeconds: 10 + HealthCheckPath: /products + HealthCheckProtocol: HTTP + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 - # This IAM Role grants the service access to register/unregister with the - # Application Load Balancer (ALB). It is based on the default documented here: - # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_IAM_role.html - ServiceRole: - Type: AWS::IAM::Role - Properties: - RoleName: !Sub ecs-service-${AWS::StackName} - Path: / - AssumeRolePolicyDocument: | - { - "Statement": [{ - "Effect": "Allow", - "Principal": { "Service": [ "ecs.amazonaws.com" ]}, - "Action": [ "sts:AssumeRole" ] - }] - } - Policies: - - PolicyName: !Sub ecs-service-${AWS::StackName} - PolicyDocument: - { - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Allow", - "Action": [ - "ec2:AuthorizeSecurityGroupIngress", - "ec2:Describe*", - "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", - "elasticloadbalancing:Describe*", - "elasticloadbalancing:RegisterInstancesWithLoadBalancer", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:RegisterTargets" - ], - "Resource": "*" - }] - } + ListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: !Ref Listener + Priority: 2 + Conditions: + - Field: path-pattern + Values: + - !Ref Path + Actions: + - TargetGroupArn: !Ref TargetGroup + Type: forward + + # This IAM Role grants the service access to register/unregister with the + # Application Load Balancer (ALB). It is based on the default documented here: + # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_IAM_role.html + ServiceRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub ecs-service-${AWS::StackName} + Path: / + AssumeRolePolicyDocument: | + { + "Statement": [{ + "Effect": "Allow", + "Principal": { "Service": [ "ecs.amazonaws.com" ]}, + "Action": [ "sts:AssumeRole" ] + }] + } + Policies: + - PolicyName: !Sub ecs-service-${AWS::StackName} + PolicyDocument: + { + "Version": "2012-10-17", + "Statement": + [ + { + "Effect": "Allow", + "Action": + [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:Describe*", + "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", + "elasticloadbalancing:Describe*", + "elasticloadbalancing:RegisterInstancesWithLoadBalancer", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:RegisterTargets", + ], + "Resource": "*", + }, + ], + } diff --git a/services/website-service/service.yaml b/services/website-service/service.yaml index 702332b1..6ad401ac 100644 --- a/services/website-service/service.yaml +++ b/services/website-service/service.yaml @@ -1,228 +1,230 @@ Description: > - This is an example of a long running ECS service that needs to connect to another ECS service (product-service) - via it's load balancer. We use environment variables to pass the URL of the product-service to this one's container(s). - -Parameters: - - VPC: - Description: The VPC that the ECS cluster is deployed to - Type: AWS::EC2::VPC::Id - - Cluster: - Description: Please provide the ECS Cluster ID that this service should run on - Type: String - - DesiredCount: - Description: How many instances of this task should we run across our cluster? - Type: Number - Default: 2 - - MaxCount: - Description: Maximum number of instances of this task we can run across our cluster - Type: Number - Default: 3 - - ProductServiceUrl: - Description: The URL of the Product Service (used to fetch product information) - Type: String - - Listener: - Description: The Application Load Balancer listener to register with - Type: String - - Path: - Description: The path to register with the Application Load Balancer - Type: String - Default: / - - ECSServiceAutoScalingRoleARN: - Description: The ECS service auto scaling role ARN - Type: String + This is an example of a long running ECS service that needs to connect to another ECS service (product-service) + via it's load balancer. We use environment variables to pass the URL of the product-service to this one's container(s). -Resources: +Parameters: + VPC: + Description: The VPC that the ECS cluster is deployed to + Type: AWS::EC2::VPC::Id + + Cluster: + Description: Please provide the ECS Cluster ID that this service should run on + Type: String + + DesiredCount: + Description: How many instances of this task should we run across our cluster? + Type: Number + Default: 2 + + MaxCount: + Description: Maximum number of instances of this task we can run across our cluster + Type: Number + Default: 3 + + ProductServiceUrl: + Description: The URL of the Product Service (used to fetch product information) + Type: String - Service: - Type: AWS::ECS::Service - DependsOn: ListenerRule - Properties: - Cluster: !Ref Cluster - Role: !Ref ServiceRole - DesiredCount: !Ref DesiredCount - TaskDefinition: !Ref TaskDefinition - LoadBalancers: - - ContainerName: "website-service" - ContainerPort: 8000 - TargetGroupArn: !Ref TargetGroup - - TaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: website-service - ContainerDefinitions: - - Name: website-service - Essential: true - Image: 275396840892.dkr.ecr.us-east-1.amazonaws.com/ecs-refarch-cloudformation/website-service:1.0.0 - Memory: 128 - Environment: - - Name: PRODUCT_SERVICE_URL - Value: !Ref ProductServiceUrl - PortMappings: - - ContainerPort: 8000 - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref CloudWatchLogsGroup - awslogs-region: !Ref AWS::Region - - CloudWatchLogsGroup: - Type: AWS::Logs::LogGroup - Properties: - LogGroupName: !Ref AWS::StackName - RetentionInDays: 365 - - TargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - Matcher: - HttpCode: 200-299 - HealthCheckIntervalSeconds: 10 - HealthCheckPath: / - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - - ListenerRule: - Type: AWS::ElasticLoadBalancingV2::ListenerRule - Properties: - ListenerArn: !Ref Listener - Priority: 1 - Conditions: - - Field: path-pattern - Values: - - !Ref Path - Actions: - - TargetGroupArn: !Ref TargetGroup - Type: forward - - # This IAM Role grants the service access to register/unregister with the - # Application Load Balancer (ALB). It is based on the default documented here: - # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_IAM_role.html - ServiceRole: - Type: AWS::IAM::Role - Properties: - RoleName: !Sub ecs-service-${AWS::StackName} - Path: / - AssumeRolePolicyDocument: | - { - "Statement": [{ - "Effect": "Allow", - "Principal": { "Service": [ "ecs.amazonaws.com" ]}, - "Action": [ "sts:AssumeRole" ] - }] - } - Policies: - - PolicyName: !Sub ecs-service-${AWS::StackName} - PolicyDocument: - { - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Allow", - "Action": [ - "ec2:AuthorizeSecurityGroupIngress", - "ec2:Describe*", - "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", - "elasticloadbalancing:Describe*", - "elasticloadbalancing:RegisterInstancesWithLoadBalancer", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:RegisterTargets" - ], - "Resource": "*" - }] - } - - ServiceScalableTarget: - Type: "AWS::ApplicationAutoScaling::ScalableTarget" - Properties: - MaxCapacity: !Ref MaxCount - MinCapacity: !Ref DesiredCount - ResourceId: !Join - - / - - - service - - !Ref Cluster - - !GetAtt Service.Name - RoleARN: !Ref ECSServiceAutoScalingRoleARN - ScalableDimension: ecs:service:DesiredCount - ServiceNamespace: ecs - - ServiceScaleOutPolicy: - Type : "AWS::ApplicationAutoScaling::ScalingPolicy" - Properties: - PolicyName: ServiceScaleOutPolicy - PolicyType: StepScaling - ScalingTargetId: !Ref ServiceScalableTarget - StepScalingPolicyConfiguration: - AdjustmentType: ChangeInCapacity - Cooldown: 1800 - MetricAggregationType: Average - StepAdjustments: - - MetricIntervalLowerBound: 0 - ScalingAdjustment: 1 - - ServiceScaleInPolicy: - Type : "AWS::ApplicationAutoScaling::ScalingPolicy" - Properties: - PolicyName: ServiceScaleInPolicy - PolicyType: StepScaling - ScalingTargetId: !Ref ServiceScalableTarget - StepScalingPolicyConfiguration: - AdjustmentType: ChangeInCapacity - Cooldown: 1800 - MetricAggregationType: Average - StepAdjustments: - - MetricIntervalUpperBound: 0 - ScalingAdjustment: -1 - - CPUScaleOutAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmName: CPU utilization greater than 90% - AlarmDescription: Alarm if cpu utilization greater than 90% of reserved cpu - Namespace: AWS/ECS - MetricName: CPUUtilization - Dimensions: - - Name: ClusterName - Value: !Ref Cluster - - Name: ServiceName - Value: !GetAtt Service.Name - Statistic: Maximum - Period: '60' - EvaluationPeriods: '3' - Threshold: '90' - ComparisonOperator: GreaterThanThreshold - AlarmActions: - - !Ref ServiceScaleOutPolicy - - CPUScaleInAlarm: - Type: AWS::CloudWatch::Alarm - Properties: - AlarmName: CPU utilization less than 70% - AlarmDescription: Alarm if cpu utilization greater than 70% of reserved cpu - Namespace: AWS/ECS - MetricName: CPUUtilization - Dimensions: - - Name: ClusterName - Value: !Ref Cluster - - Name: ServiceName - Value: !GetAtt Service.Name - Statistic: Maximum - Period: '60' - EvaluationPeriods: '10' - Threshold: '70' - ComparisonOperator: LessThanThreshold - AlarmActions: - - !Ref ServiceScaleInPolicy + Listener: + Description: The Application Load Balancer listener to register with + Type: String + + Path: + Description: The path to register with the Application Load Balancer + Type: String + Default: / + + ECSServiceAutoScalingRoleARN: + Description: The ECS service auto scaling role ARN + Type: String + +Resources: + Service: + Type: AWS::ECS::Service + DependsOn: ListenerRule + Properties: + Cluster: !Ref Cluster + Role: !Ref ServiceRole + DesiredCount: !Ref DesiredCount + TaskDefinition: !Ref TaskDefinition + LoadBalancers: + - ContainerName: "website-service" + ContainerPort: 8000 + TargetGroupArn: !Ref TargetGroup + + TaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: website-service + ContainerDefinitions: + - Name: website-service + Essential: true + Image: 275396840892.dkr.ecr.us-east-1.amazonaws.com/ecs-refarch-cloudformation/website-service:1.0.0 + Memory: 128 + Environment: + - Name: PRODUCT_SERVICE_URL + Value: !Ref ProductServiceUrl + PortMappings: + - ContainerPort: 8000 + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref CloudWatchLogsGroup + awslogs-region: !Ref AWS::Region + + CloudWatchLogsGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Ref AWS::StackName + RetentionInDays: 365 + + TargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + VpcId: !Ref VPC + Port: 80 + Protocol: HTTP + Matcher: + HttpCode: 200-299 + HealthCheckIntervalSeconds: 10 + HealthCheckPath: / + HealthCheckProtocol: HTTP + HealthCheckTimeoutSeconds: 5 + HealthyThresholdCount: 2 + + ListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + ListenerArn: !Ref Listener + Priority: 1 + Conditions: + - Field: path-pattern + Values: + - !Ref Path + Actions: + - TargetGroupArn: !Ref TargetGroup + Type: forward + + # This IAM Role grants the service access to register/unregister with the + # Application Load Balancer (ALB). It is based on the default documented here: + # http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service_IAM_role.html + ServiceRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub ecs-service-${AWS::StackName} + Path: / + AssumeRolePolicyDocument: | + { + "Statement": [{ + "Effect": "Allow", + "Principal": { "Service": [ "ecs.amazonaws.com" ]}, + "Action": [ "sts:AssumeRole" ] + }] + } + Policies: + - PolicyName: !Sub ecs-service-${AWS::StackName} + PolicyDocument: + { + "Version": "2012-10-17", + "Statement": + [ + { + "Effect": "Allow", + "Action": + [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:Describe*", + "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", + "elasticloadbalancing:Describe*", + "elasticloadbalancing:RegisterInstancesWithLoadBalancer", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:RegisterTargets", + ], + "Resource": "*", + }, + ], + } + + ServiceScalableTarget: + Type: "AWS::ApplicationAutoScaling::ScalableTarget" + Properties: + MaxCapacity: !Ref MaxCount + MinCapacity: !Ref DesiredCount + ResourceId: !Join + - / + - - service + - !Ref Cluster + - !GetAtt Service.Name + RoleARN: !Ref ECSServiceAutoScalingRoleARN + ScalableDimension: ecs:service:DesiredCount + ServiceNamespace: ecs + + ServiceScaleOutPolicy: + Type: "AWS::ApplicationAutoScaling::ScalingPolicy" + Properties: + PolicyName: ServiceScaleOutPolicy + PolicyType: StepScaling + ScalingTargetId: !Ref ServiceScalableTarget + StepScalingPolicyConfiguration: + AdjustmentType: ChangeInCapacity + Cooldown: 1800 + MetricAggregationType: Average + StepAdjustments: + - MetricIntervalLowerBound: 0 + ScalingAdjustment: 1 + + ServiceScaleInPolicy: + Type: "AWS::ApplicationAutoScaling::ScalingPolicy" + Properties: + PolicyName: ServiceScaleInPolicy + PolicyType: StepScaling + ScalingTargetId: !Ref ServiceScalableTarget + StepScalingPolicyConfiguration: + AdjustmentType: ChangeInCapacity + Cooldown: 1800 + MetricAggregationType: Average + StepAdjustments: + - MetricIntervalUpperBound: 0 + ScalingAdjustment: -1 + + CPUScaleOutAlarm: + Type: AWS::CloudWatch::Alarm + Properties: + AlarmName: CPU utilization greater than 90% + AlarmDescription: Alarm if cpu utilization greater than 90% of reserved cpu + Namespace: AWS/ECS + MetricName: CPUUtilization + Dimensions: + - Name: ClusterName + Value: !Ref Cluster + - Name: ServiceName + Value: !GetAtt Service.Name + Statistic: Maximum + Period: "60" + EvaluationPeriods: "3" + Threshold: "90" + ComparisonOperator: GreaterThanThreshold + AlarmActions: + - !Ref ServiceScaleOutPolicy + + CPUScaleInAlarm: + Type: AWS::CloudWatch::Alarm + Properties: + AlarmName: CPU utilization less than 70% + AlarmDescription: Alarm if cpu utilization greater than 70% of reserved cpu + Namespace: AWS/ECS + MetricName: CPUUtilization + Dimensions: + - Name: ClusterName + Value: !Ref Cluster + - Name: ServiceName + Value: !GetAtt Service.Name + Statistic: Maximum + Period: "60" + EvaluationPeriods: "10" + Threshold: "70" + ComparisonOperator: LessThanThreshold + AlarmActions: + - !Ref ServiceScaleInPolicy