1
0
mirror of https://github.com/ebosas/microservices.git synced 2025-07-12 22:41:13 +02:00

Pipeline deployment type

This commit is contained in:
ebosas
2021-11-03 08:35:22 +02:00
parent 3f2256e38b
commit f8b7608adc
5 changed files with 998 additions and 7 deletions

214
deployments/cluster-ecs.yml Normal file
View File

@ -0,0 +1,214 @@
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. Example: staging, qa, or production"
InstanceType:
Type: String
Default: t2.micro
Description: Class of EC2 instance used to host containers. Choose t2 for testing, m5 for general purpose, c5 for CPU intensive services, and r5 for memory intensive services
AllowedValues: [ t2.micro, t2.small, t2.medium, t2.large, t2.xlarge, t2.2xlarge,
m5.large, m5.xlarge, m5.2xlarge, m5.4xlarge, m5.12xlarge, m5.24xlarge,
c5.large, c5.xlarge, c5.2xlarge, c5.4xlarge, c5.9xlarge, c5.18xlarge,
r5.large, r5.xlarge, r5.2xlarge, r5.4xlarge, r5.12xlarge, r5.24xlarge ]
ConstraintDescription: Please choose a valid instance type.
DesiredCapacity:
Type: Number
Default: '1'
Description: Number of EC2 instances to launch in your ECS cluster.
MaxSize:
Type: Number
Default: '3'
Description: Maximum number of EC2 instances that can be launched in your ECS cluster.
ECSAMI:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id
Description: The Amazon Machine Image ID used for the cluster, leave it as the default value to get the latest AMI
Resources:
# ECS Resources
ECSCluster:
Type: AWS::ECS::Cluster
# Autoscaling group. This launches the actual EC2 instances that will register
# themselves as members of the cluster, and run the docker containers.
ECSAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
# Protection from scale-in is required with capacity providers but
# the auto scaling group will have to be manually removed when deleting
# the ec2 cluster stack in cloudformation.
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: !Ref 'MaxSize'
DesiredCapacity: !Ref 'DesiredCapacity'
CreationPolicy:
ResourceSignal:
Timeout: PT15M
UpdatePolicy:
AutoScalingReplacingUpdate:
WillReplace: true
ContainerInstances:
Type: AWS::AutoScaling::LaunchConfiguration
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
Properties:
Path: /
Roles: [!Ref 'EC2Role']
# Capacity provider. Automatically manages the scaling of the EC2 instances.
ECSCapacityProvider:
Type: AWS::ECS::CapacityProvider
Properties:
AutoScalingGroupProvider:
AutoScalingGroupArn: !Ref ECSAutoScalingGroup
ManagedScaling:
MaximumScalingStepSize: 2
MinimumScalingStepSize: 1
Status: ENABLED
TargetCapacity: 100
ManagedTerminationProtection: ENABLED
ECSClusterCapProvAssoc:
Type: AWS::ECS::ClusterCapacityProviderAssociations
Properties:
Cluster: !Ref ECSCluster
CapacityProviders:
- !Ref ECSCapacityProvider
DefaultCapacityProviderStrategy:
- CapacityProvider: !Ref ECSCapacityProvider
Weight: 100
# A role used to allow AWS Autoscaling to inspect stats and adjust scaleable targets
# on your AWS account
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 the EC2 hosts. This allows the ECS agent on the EC2 hosts
# to communciate with the ECS control plane, as well as download the docker
# images from ECR to run on your host.
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
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:GetAuthorizationToken'
- 'ecr:BatchGetImage'
- 'ecr:GetDownloadUrlForLayer'
Resource: '*'
# This is an IAM role which authorizes ECS to manage resources on your
# account on your behalf, such as updating your load balancer with the
# details of where your containers are, so that traffic can reach your
# containers.
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: '*'
# These are the values output by the CloudFormation template. Be careful
# about changing any of them, because of them are exported with specific
# names so that the other task related CF templates can use them.
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

View File

@ -10,6 +10,10 @@ Parameters:
Type: String
EnvironmentName:
Type: String
DeploymentType:
Type: String
Default: fargate
AllowedValues: [ecs, fargate]
Resources:
# Create ECR respositories to hold built docker images
@ -261,7 +265,7 @@ Resources:
- Name: Network
# Deploy the base resources: databases, the load balancer,
# and the Fargate cluster
# and the ECS/Fargate cluster
- Name: BaseResources
Actions:
# Deploy the resources: Rabbit, Redis, and Postgres
@ -308,7 +312,7 @@ Resources:
OutputArtifacts:
- Name: LoadBalancer
# Deploy the Fargate cluster
# Deploy the ECS/Fargate cluster
- Name: DeployCluster
ActionTypeId:
Category: Deploy
@ -319,7 +323,7 @@ Resources:
ActionMode: CREATE_UPDATE
RoleArn: !GetAtt CloudFormationDeployRole.Arn
StackName: !Sub ${EnvironmentName}-Cluster
TemplatePath: Source::deployments/cluster-fargate.yml
TemplatePath: !Sub Source::deployments/cluster-${DeploymentType}.yml
Capabilities: CAPABILITY_IAM
ParameterOverrides: !Sub |
{
@ -347,7 +351,7 @@ Resources:
- Name: BuildOutput
RunOrder: 1
# Finally we deploy the Fargate services to the cluster
# Finally we deploy the ECS/Fargate services to the cluster
- Name: Deploy
Actions:
# Deploy the server service
@ -361,7 +365,7 @@ Resources:
ActionMode: CREATE_UPDATE
RoleArn: !GetAtt CloudFormationDeployRole.Arn
StackName: !Sub ${EnvironmentName}-ServerService
TemplatePath: Source::deployments/services-fargate/server.yml
TemplatePath: !Sub Source::deployments/services-${DeploymentType}/server.yml
Capabilities: CAPABILITY_IAM
ParameterOverrides: !Sub |
{
@ -385,7 +389,7 @@ Resources:
ActionMode: CREATE_UPDATE
RoleArn: !GetAtt CloudFormationDeployRole.Arn
StackName: !Sub ${EnvironmentName}-CacheService
TemplatePath: Source::deployments/services-fargate/cache.yml
TemplatePath: !Sub Source::deployments/services-${DeploymentType}/cache.yml
Capabilities: CAPABILITY_IAM
ParameterOverrides: !Sub |
{
@ -409,7 +413,7 @@ Resources:
ActionMode: CREATE_UPDATE
RoleArn: !GetAtt CloudFormationDeployRole.Arn
StackName: !Sub ${EnvironmentName}-DatabaseService
TemplatePath: Source::deployments/services-fargate/database.yml
TemplatePath: !Sub Source::deployments/services-${DeploymentType}/database.yml
Capabilities: CAPABILITY_IAM
ParameterOverrides: !Sub |
{

View File

@ -0,0 +1,237 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service into an ECS cluster behind a public load balancer.
Parameters:
EnvironmentName:
Type: String
Default: production
Description: The name of the environment to add this service to
ServiceName:
Type: String
Default: cache
Description: A name for the service
# ImageUrl:
# Type: String
# Description: The url of a docker image that contains the application process that
# will handle the traffic for this service
ContainerCpu:
Type: Number
Default: 256
Description: How much CPU to give the container. 1024 is 1 CPU
ContainerMemory:
Type: Number
Default: 230
Description: How much memory in megabytes to give the container
DesiredCount:
Type: Number
Default: 1
Description: How many copies of the service task to run
Role:
Type: String
Default: ""
Description: (Optional) An IAM role to give the service's containers if the code within needs to
access other AWS resources like S3 buckets, DynamoDB tables, etc
Conditions:
HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
Resources:
# A log group for storing the stdout logs from this service's containers
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub ${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'
TaskRoleArn:
Fn::If:
- 'HasCustomRole'
- !Ref 'Role'
- !Ref "AWS::NoValue"
ContainerDefinitions:
- Name: !Ref 'ServiceName'
Cpu: !Ref 'ContainerCpu'
Memory: !Ref 'ContainerMemory'
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/microservices/${ServiceName}:latest
# Image: !Ref ImageUrl
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Ref 'ServiceName'
Environment:
- Name: RABBIT_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/rabbiturl}}'
- Name: REDIS_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/redisurl}}'
# 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
Properties:
ServiceName: !Ref 'ServiceName'
Cluster:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 75
DesiredCount: !Ref 'DesiredCount'
TaskDefinition: !Ref 'TaskDefinition'
PlacementStrategies:
- Field: memory
Type: binpack
# Enable autoscaling for this service
ScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: Service
Properties:
ServiceNamespace: 'ecs'
ScalableDimension: 'ecs:service:DesiredCount'
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
MinCapacity: 1
MaxCapacity: 10
RoleARN:
Fn::ImportValue: !Sub ${EnvironmentName}:AutoscalingRole
# Create scaling policies for the service
ScaleDownPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- down
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalUpperBound: 0
ScalingAdjustment: -1
MetricAggregationType: 'Average'
Cooldown: 60
ScaleUpPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- up
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalLowerBound: 0
MetricIntervalUpperBound: 15
ScalingAdjustment: 1
- MetricIntervalLowerBound: 15
MetricIntervalUpperBound: 25
ScalingAdjustment: 2
- MetricIntervalLowerBound: 25
ScalingAdjustment: 3
MetricAggregationType: 'Average'
Cooldown: 60
# Create alarms to trigger these policies
LowCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - low-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "Low CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 20
ComparisonOperator: LessThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleDownPolicy
HighCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - high-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "High CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 70
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleUpPolicy

View File

@ -0,0 +1,237 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service into an ECS cluster behind a public load balancer.
Parameters:
EnvironmentName:
Type: String
Default: production
Description: The name of the environment to add this service to
ServiceName:
Type: String
Default: database
Description: A name for the service
# ImageUrl:
# Type: String
# Description: The url of a docker image that contains the application process that
# will handle the traffic for this service
ContainerCpu:
Type: Number
Default: 256
Description: How much CPU to give the container. 1024 is 1 CPU
ContainerMemory:
Type: Number
Default: 230
Description: How much memory in megabytes to give the container
DesiredCount:
Type: Number
Default: 1
Description: How many copies of the service task to run
Role:
Type: String
Default: ""
Description: (Optional) An IAM role to give the service's containers if the code within needs to
access other AWS resources like S3 buckets, DynamoDB tables, etc
Conditions:
HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
Resources:
# A log group for storing the stdout logs from this service's containers
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub ${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'
TaskRoleArn:
Fn::If:
- 'HasCustomRole'
- !Ref 'Role'
- !Ref "AWS::NoValue"
ContainerDefinitions:
- Name: !Ref 'ServiceName'
Cpu: !Ref 'ContainerCpu'
Memory: !Ref 'ContainerMemory'
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/microservices/${ServiceName}:latest
# Image: !Ref ImageUrl
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Ref 'ServiceName'
Environment:
- Name: RABBIT_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/rabbiturl}}'
- Name: POSTGRES_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/postgresurl}}'
# 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
Properties:
ServiceName: !Ref 'ServiceName'
Cluster:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 75
DesiredCount: !Ref 'DesiredCount'
TaskDefinition: !Ref 'TaskDefinition'
PlacementStrategies:
- Field: memory
Type: binpack
# Enable autoscaling for this service
ScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: Service
Properties:
ServiceNamespace: 'ecs'
ScalableDimension: 'ecs:service:DesiredCount'
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
MinCapacity: 1
MaxCapacity: 10
RoleARN:
Fn::ImportValue: !Sub ${EnvironmentName}:AutoscalingRole
# Create scaling policies for the service
ScaleDownPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- down
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalUpperBound: 0
ScalingAdjustment: -1
MetricAggregationType: 'Average'
Cooldown: 60
ScaleUpPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- up
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalLowerBound: 0
MetricIntervalUpperBound: 15
ScalingAdjustment: 1
- MetricIntervalLowerBound: 15
MetricIntervalUpperBound: 25
ScalingAdjustment: 2
- MetricIntervalLowerBound: 25
ScalingAdjustment: 3
MetricAggregationType: 'Average'
Cooldown: 60
# Create alarms to trigger these policies
LowCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - low-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "Low CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 20
ComparisonOperator: LessThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleDownPolicy
HighCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - high-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "High CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 70
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleUpPolicy

View File

@ -0,0 +1,299 @@
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service into an ECS cluster behind a public load balancer.
Parameters:
EnvironmentName:
Type: String
Default: production
Description: The name of the environment to add this service to
ServiceName:
Type: String
Default: server
Description: A name for the service
# ImageUrl:
# Type: String
# Description: The url of a docker image 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
ContainerMemory:
Type: Number
Default: 230
Description: How much memory in megabytes to give the container
Path:
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.
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: 1
Description: How many copies of the service task to run
Role:
Type: String
Default: ""
Description: (Optional) An IAM role to give the service's containers if the code within needs to
access other AWS resources like S3 buckets, DynamoDB tables, etc
Conditions:
HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
Resources:
# A log group for storing the stdout logs from this service's containers
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub ${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'
TaskRoleArn:
Fn::If:
- 'HasCustomRole'
- !Ref 'Role'
- !Ref "AWS::NoValue"
ContainerDefinitions:
- Name: !Ref 'ServiceName'
Cpu: !Ref 'ContainerCpu'
Memory: !Ref 'ContainerMemory'
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/microservices/${ServiceName}:latest
# Image: !Ref ImageUrl
PortMappings:
- ContainerPort: !Ref 'ContainerPort'
LogConfiguration:
LogDriver: 'awslogs'
Options:
awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
awslogs-region: !Ref 'AWS::Region'
awslogs-stream-prefix: !Ref 'ServiceName'
Environment:
- Name: RABBIT_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/rabbiturl}}'
- Name: REDIS_URL
Value: !Sub '{{resolve:ssm:/microservices/${EnvironmentName}/redisurl}}'
- Name: SERVER_ADDR
Value: 0.0.0.0:80
# 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 ${EnvironmentName}:ClusterName
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 75
DesiredCount: !Ref 'DesiredCount'
TaskDefinition: !Ref 'TaskDefinition'
PlacementStrategies:
- Field: memory
Type: binpack
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: 6
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Name: !Ref 'ServiceName'
Port: 80
Protocol: HTTP
UnhealthyThresholdCount: 2
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 60
VpcId:
Fn::ImportValue: !Sub ${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:
Fn::ImportValue: !Sub ${EnvironmentName}:PublicListener
Priority: !Ref 'Priority'
# Enable autoscaling for this service
ScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: Service
Properties:
ServiceNamespace: 'ecs'
ScalableDimension: 'ecs:service:DesiredCount'
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
MinCapacity: 1
MaxCapacity: 10
RoleARN:
Fn::ImportValue: !Sub ${EnvironmentName}:AutoscalingRole
# Create scaling policies for the service
ScaleDownPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- down
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalUpperBound: 0
ScalingAdjustment: -1
MetricAggregationType: 'Average'
Cooldown: 60
ScaleUpPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: ScalableTarget
Properties:
PolicyName:
Fn::Join:
- '/'
- - scale
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
- up
PolicyType: StepScaling
ResourceId:
Fn::Join:
- '/'
- - service
- Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
- !Ref 'ServiceName'
ScalableDimension: 'ecs:service:DesiredCount'
ServiceNamespace: 'ecs'
StepScalingPolicyConfiguration:
AdjustmentType: 'ChangeInCapacity'
StepAdjustments:
- MetricIntervalLowerBound: 0
MetricIntervalUpperBound: 15
ScalingAdjustment: 1
- MetricIntervalLowerBound: 15
MetricIntervalUpperBound: 25
ScalingAdjustment: 2
- MetricIntervalLowerBound: 25
ScalingAdjustment: 3
MetricAggregationType: 'Average'
Cooldown: 60
# Create alarms to trigger these policies
LowCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - low-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "Low CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 20
ComparisonOperator: LessThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleDownPolicy
HighCpuUsageAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Join:
- '-'
- - high-cpu
- !Ref 'EnvironmentName'
- !Ref 'ServiceName'
AlarmDescription:
Fn::Join:
- ' '
- - "High CPU utilization for service"
- !Ref 'ServiceName'
- "in environment"
- !Ref 'EnvironmentName'
MetricName: CPUUtilization
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value: !Ref 'ServiceName'
- Name: ClusterName
Value:
Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
Statistic: Average
Period: 60
EvaluationPeriods: 1
Threshold: 70
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- !Ref ScaleUpPolicy