320 lines
10 KiB
YAML
320 lines
10 KiB
YAML
AWSTemplateFormatVersion: '2010-09-09'
|
|
Description: Socket.io chat service
|
|
Parameters:
|
|
EnvironmentName:
|
|
Type: String
|
|
Default: production
|
|
Description: A name for the environment that this cloudformation will be part of.
|
|
Used to locate other resources in the same environment.
|
|
ServiceName:
|
|
Type: String
|
|
Default: chat
|
|
Description: A name for the service
|
|
ImageUrl:
|
|
Type: String
|
|
Default: nginx
|
|
Description: The url of a docker image that contains the application process that
|
|
will handle the traffic for this service
|
|
ContainerPort:
|
|
Type: Number
|
|
Default: 3000
|
|
Description: What port number the application inside the docker container is binding to
|
|
ContainerCpu:
|
|
Type: Number
|
|
Default: 1024
|
|
Description: How much CPU to give the container. 1024 is 1 CPU
|
|
ContainerMemory:
|
|
Type: Number
|
|
Default: 2048
|
|
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: 2
|
|
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 container logs for this service
|
|
LogGroup:
|
|
Type: AWS::Logs::LogGroup
|
|
Properties:
|
|
LogGroupName: !Join ['-', [!Ref 'EnvironmentName', 'service', !Ref 'ServiceName']]
|
|
|
|
# The task definition. This is a simple metadata description of what
|
|
# container to run, and what resource requirements it has.
|
|
TaskDefinition:
|
|
Type: AWS::ECS::TaskDefinition
|
|
Properties:
|
|
Family: !Ref 'ServiceName'
|
|
Cpu: !Ref 'ContainerCpu'
|
|
Memory: !Ref 'ContainerMemory'
|
|
NetworkMode: awsvpc
|
|
RequiresCompatibilities:
|
|
- FARGATE
|
|
ExecutionRoleArn:
|
|
Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'ECSTaskExecutionRole']]
|
|
TaskRoleArn:
|
|
Fn::If:
|
|
- 'HasCustomRole'
|
|
- !Ref 'Role'
|
|
- !Ref "AWS::NoValue"
|
|
ContainerDefinitions:
|
|
- Name: !Ref 'ServiceName'
|
|
Cpu: !Ref 'ContainerCpu'
|
|
Memory: !Ref 'ContainerMemory'
|
|
Image: !Ref 'ImageUrl'
|
|
Environment:
|
|
- Name: REDIS_ENDPOINT
|
|
Value:
|
|
Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'RedisEndpoint']]
|
|
PortMappings:
|
|
- ContainerPort: !Ref 'ContainerPort'
|
|
LogConfiguration:
|
|
LogDriver: 'awslogs'
|
|
Options:
|
|
awslogs-group: !Join ['-', [!Ref 'EnvironmentName', 'service', !Ref 'ServiceName']]
|
|
awslogs-region: !Ref 'AWS::Region'
|
|
awslogs-stream-prefix: !Ref 'ServiceName'
|
|
|
|
# The service. The service is a resource which allows you to run multiple
|
|
# copies of a type of task, and gather up their logs and metrics, as well
|
|
# as monitor the number of running tasks and replace any that have crashed
|
|
Service:
|
|
Type: AWS::ECS::Service
|
|
DependsOn: LoadBalancerRule
|
|
Properties:
|
|
ServiceName: !Ref 'ServiceName'
|
|
Cluster:
|
|
Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'ClusterName']]
|
|
LaunchType: FARGATE
|
|
DeploymentConfiguration:
|
|
MaximumPercent: 200
|
|
MinimumHealthyPercent: 75
|
|
DesiredCount: !Ref 'DesiredCount'
|
|
NetworkConfiguration:
|
|
AwsvpcConfiguration:
|
|
AssignPublicIp: ENABLED
|
|
SecurityGroups:
|
|
- Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'FargateContainerSecurityGroup']]
|
|
Subnets:
|
|
- Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'PublicSubnetOne']]
|
|
- Fn::ImportValue:
|
|
!Join [':', [!Ref 'EnvironmentName', 'PublicSubnetTwo']]
|
|
TaskDefinition: !Ref 'TaskDefinition'
|
|
LoadBalancers:
|
|
- ContainerName: !Ref 'ServiceName'
|
|
ContainerPort: !Ref 'ContainerPort'
|
|
TargetGroupArn: !Ref 'TargetGroup'
|
|
|
|
# A target group. This is used for keeping track of all the tasks, and
|
|
# what IP addresses / port numbers they have. You can query it yourself,
|
|
# to use the addresses yourself, but most often this target group is just
|
|
# connected to an application load balancer, or network load balancer, so
|
|
# it can automatically distribute traffic across all the targets.
|
|
TargetGroup:
|
|
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
|
Properties:
|
|
HealthCheckIntervalSeconds: 6
|
|
HealthCheckPath: /
|
|
HealthCheckProtocol: HTTP
|
|
HealthCheckTimeoutSeconds: 5
|
|
HealthyThresholdCount: 2
|
|
TargetType: ip
|
|
Name: !Ref 'ServiceName'
|
|
Port: 80
|
|
Protocol: HTTP
|
|
UnhealthyThresholdCount: 2
|
|
TargetGroupAttributes:
|
|
- Key: stickiness.enabled
|
|
Value: true
|
|
- Key: deregistration_delay.timeout_seconds
|
|
Value: 30
|
|
VpcId:
|
|
Fn::ImportValue:
|
|
!Join [':', [!Ref '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:
|
|
!Join [':', [!Ref '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: !Join [':', [!Ref 'EnvironmentName', 'ClusterName']]
|
|
- !Ref 'ServiceName'
|
|
MinCapacity: 2
|
|
MaxCapacity: 10
|
|
RoleARN:
|
|
Fn::ImportValue:
|
|
!Join [':', [!Ref '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: !Join [':', [!Ref '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: !Join [':', [!Ref '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 stack"
|
|
- !Ref 'EnvironmentName'
|
|
MetricName: CPUUtilization
|
|
Namespace: AWS/ECS
|
|
Dimensions:
|
|
- Name: ServiceName
|
|
Value: !Ref 'ServiceName'
|
|
- Name: ClusterName
|
|
Value:
|
|
Fn::ImportValue: !Join [':', [!Ref '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 stack"
|
|
- !Ref 'EnvironmentName'
|
|
MetricName: CPUUtilization
|
|
Namespace: AWS/ECS
|
|
Dimensions:
|
|
- Name: ServiceName
|
|
Value: !Ref 'ServiceName'
|
|
- Name: ClusterName
|
|
Value:
|
|
Fn::ImportValue: !Join [':', [!Ref 'EnvironmentName', 'ClusterName']]
|
|
Statistic: Average
|
|
Period: 60
|
|
EvaluationPeriods: 1
|
|
Threshold: 70
|
|
ComparisonOperator: GreaterThanOrEqualToThreshold
|
|
AlarmActions:
|
|
- !Ref ScaleUpPolicy
|