Dependency: This article requires an understanding of the basics of AWS architecture design
AWS Fargate
AWS Fargate is a technology that works with Amazon ECS so that you don't have to manage a server or cluster of Amazon EC2 instances to run containers . With Fargate, you no longer have to provision, provision, or scale a cluster of virtual machines to run containers. This eliminates the need to choose server types, determine when to scale your cluster, and optimize cluster packaging.
AWS ECS
Amazon Elastic Container Service (Amazon ECS) is a highly scalable fast container management service. You can use it to run, stop, and manage containers on your cluster. With Amazon ECS, your containers are defined in task definitions that run individual tasks or tasks within a service. In this context, a service is a configuration that you can use to run and maintain a specified number of tasks concurrently in a cluster. You can run tasks and services on serverless infrastructure managed by AWS Fargate. Or, for greater control over your infrastructure, you can run tasks and services on managed clusters of Amazon EC2 instances.
Create an IAM role
additional strategy
AmazonECSTaskExecutionRolePolicy
AmazonSSMFullAccess
EC2InstanceProfileForImageBuilderECRContainerBuilds
AmazonECS_FullAccess
AmazonS3FullAccess
AmazonSNSFullAccess
CloudWatchFullAccess
trust relationship
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ecs-tasks.amazonaws.com",
"apigateway.amazonaws.com",
"ecs.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Create ECR
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Environment:
Type: String
Default: DEV
EnvironmentName:
Type: String
Default: d
CustomerName:
Description: The name of the customer
Type: String
#TODO:
Default: your-company-name
ProjectName:
Description: The name of the project
Type: String
#TODO:
Default: your-project-name
Resources:
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName:
!Join [ "-", [ !Ref CustomerName, !Ref ProjectName, your-Repository-name, !Ref EnvironmentName, "ecr", ], ]
Tags:
- Key: ApplName
Value: your-app-name
Create a Cluster
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Environment:
Type: String
Default: DEV
EnvironmentName:
Type: String
Default: d
CustomerName:
Description: The name of the customer
Type: String
#TODO:
Default: your-company-name
ProjectName:
Description: The name of the project
Type: String
#TODO:
Default: your-project-name
ContainerInsights:
Type: String
AllowedValues:
- enabled
- disabled
#HACK:Development environment is disabled, production environment is enabled
Default: disabled
Resources:
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterSettings:
- Name: containerInsights
Value: !Ref ContainerInsights
ClusterName: !Join [ '-', [ !Ref CustomerName, !Ref ProjectName, !Ref EnvironmentName, 'cluster'] ]
Tags:
- Key: ApplName
Value: your-app-name
Create ECS
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Environment:
Type: String
Default: DEV
EnvironmentName:
Type: String
AllowedValues:
Default: d
SubProjectName:
Description: The name of the sub project
Type: String
#TODO:
Default: your-subsystem-name
CustomerName:
Description: The name of the customer
Type: String
#TODO:
Default: your-company-name
ProjectName:
Description: The name of the project
Type: String
#TODO:
Default: your-project-name
ProjectType:
Type: String
#TODO:
Default: your-domain-name
HostedZoneName:
Description: The name of route53 hosted
Type: String
#TODO:
Default: dev.xxx.cn.
ServiceSubnetIds:
Description: The subnet ids of the ECS service
Type: List<AWS::EC2::Subnet::Id>
#TODO:
Default: subnet-xxxxxxx,subnet-xxxxxxx
VPCID:
Type: AWS::EC2::VPC::Id
#TODO:
Default: vpc-xxxxxxxx
FargateSecurityGroups:
Description: security groups for fargate
Type: List<AWS::EC2::SecurityGroup::Id>
#TODO:
Default: sg-xxxxxxxx
S3BktName:
Type: String
Default: ""
Cpu:
Type: Number
Default: 512
Memory:
Type: Number
Default: 1024
CFDomain:
Type: String
#TODO:
Default: "https://www.xxxx.com.cn/"
ALBSubnetsIds:
Description: The subnet ids of the ALB
Type:
List<AWS::EC2::Subnet::Id>
#TODO:
Default: subnet-xxxxxxx, subnet-xxxxxxxx
AlbSecurityGroups:
Description: Security group for ALB
Type:
List<AWS::EC2::SecurityGroup::Id>
#TODO:
Default: sg-xxxxxxxx
AutoScalingRoleARN:
Type: String
Default: AWSServiceRoleForApplicationAutoScaling_xxxxxxx
Certificate:
Type:
String
#TODO:
Default: xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
Resources:
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/ecs/${CustomerName}-${ProjectName}-${SubProjectName}-${EnvironmentName}-task'
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Tags:
- Key: ApplName
Value: your-app-name
Family:
!Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "task", ], ]
Cpu: !Ref Cpu
Memory: !Ref Memory
NetworkMode: awsvpc
ExecutionRoleArn: !Sub arn:aws-cn:iam::${
AWS::AccountId}:role/${
CustomerName}-${
ProjectName}-ecs-task-role-${
EnvironmentName}-iamr
TaskRoleArn: !Sub arn:aws-cn:iam::${
AWS::AccountId}:role/${
CustomerName}-${
ProjectName}-ecs-task-role-${
EnvironmentName}-iamr
ContainerDefinitions:
- Name:
!Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "container", ], ]
Image: !Sub ${
AWS::AccountId}.dkr.ecr.${
AWS::Region}.amazonaws.com.cn/${
CustomerName}-${
ProjectName}-${
SubProjectName}-${
EnvironmentName}-ecr:latest
PortMappings:
- ContainerPort: 80
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: ecs
Environment:
- Name: ECS_ROLE_ARN
Value: !Sub arn:aws-cn:iam::${
AWS::AccountId}:role/${
CustomerName}-${
ProjectName}-ecs-task-role-${
EnvironmentName}-iamr
- Name: S3_BKT_NAME
Value: !Ref S3BktName
- Name: CF_DOMAIN
Value: !Ref CFDomain
RequiresCompatibilities:
- FARGATE
Service:
Type: AWS::ECS::Service
DependsOn:
- LoadBalancerListenerHTTP
- LoadBalancerListenerHTTPS
Properties:
Tags:
- Key: ApplName
Value: your-app-name
PropagateTags: TASK_DEFINITION
ServiceName:
!Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "service", ], ]
Cluster: !Sub arn:aws-cn:ecs:${
AWS::Region}:${
AWS::AccountId}:cluster/${
CustomerName}-${
ProjectName}-${
EnvironmentName}-cluster
TaskDefinition: !Ref TaskDefinition
DeploymentConfiguration:
MinimumHealthyPercent: 100
MaximumPercent: 200
#CircuitBreaker Use
DeploymentCircuitBreaker:
Enable: True
Rollback: True
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
Subnets: !Ref ServiceSubnetIds
SecurityGroups: !Ref FargateSecurityGroups
LoadBalancers:
- ContainerName: !Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "container", ], ]
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
AutoScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MinCapacity: 1
MaxCapacity: 5
ResourceId: !Sub service/${
CustomerName}-${
ProjectName}-${
EnvironmentName}-cluster/${
Service.Name}
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
RoleARN: !Sub arn:aws-cn:iam::${
AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/${
AutoScalingRoleARN}
AutoScalingPolicyCPU:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: AutoScalingTarget
Properties:
PolicyName:
!Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "autoscaling-policy-cpu", ], ]
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref AutoScalingTarget
TargetTrackingScalingPolicyConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleInCooldown: 10
ScaleOutCooldown: 10
TargetValue: 50
AutoScalingPolicyMemory:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn: AutoScalingTarget
Properties:
PolicyName: !Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "autoscaling-policy-mem", ], ]
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref AutoScalingTarget
TargetTrackingScalingPolicyConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageMemoryUtilization
ScaleInCooldown: 10
ScaleOutCooldown: 10
TargetValue: 50
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "group", ], ]
HealthCheckEnabled: true
HealthCheckIntervalSeconds: 60
HealthCheckPath: /healthcheck
HealthCheckPort: 80
HealthCheckProtocol: HTTP
Port: 80
Protocol: HTTP
HealthCheckTimeoutSeconds: 30
HealthyThresholdCount: 3
Tags:
- Key: ApplName
Value: your-app-name
TargetType: ip
VpcId: !Ref VPCID
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Tags:
- Key: ApplName
Value: your-app-name
Name: !Join [ "-", [ !Ref CustomerName, !Ref ProjectName, !Ref SubProjectName, !Ref EnvironmentName, "alb", ], ]
Subnets: !Ref ALBSubnetsIds
SecurityGroups: !Ref AlbSecurityGroups
LoadBalancerListenerHTTP:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: "redirect"
RedirectConfig:
Protocol: "HTTPS"
Port: 443
Host: "#{host}"
Path: "/#{path}"
Query: "#{query}"
StatusCode: "HTTP_301"
LoadBalancerListenerHTTPS:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref LoadBalancer
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-TLS-1-2-2017-01
Certificates:
- CertificateArn: !Sub arn:aws-cn:acm:${
AWS::Region}:${
AWS::AccountId}:certificate/${
Certificate}
Rount53DNSRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Ref HostedZoneName
Comment: subsystem DNS.
Name: !Sub ${
ProjectName}${
ProjectType}.${
HostedZoneName}
Type: A
AliasTarget:
HostedZoneId: !GetAtt "LoadBalancer.CanonicalHostedZoneID"
DNSName: !GetAtt "LoadBalancer.DNSName"