最近在写一些nodejs的东西,尝试用docker去部署,研究了一下如何用AWS ECS做部署和自动扩展,跟传统的使用EC2来做部署使用ASG做扩展还是有一些不同的。
AWS ECS基本概念
Amazon EC2 Container Service 是基于docker的具有高可扩展性,快速的容器管理服务,可以让你在EC2 instance集群中简单快速的部署和扩展应用程序。
ECS中有一些基本概念需要先了解一下
- ECR - Elastic Container Registry 用来建立一个安全,可扩展,高可用的应用程序私有docker registry。
- Cluster - 逻辑上的一组由EC2 instance组成的集群,你的container跑在这些集群上面。
- Service - 在指定的cluster上来维护和启动一定数量的任务容器实例的服务。
- Task Definition - 定义了由service维护的任务,比如image是哪个,CPU和Memory如何分配,端口号如何映射,容器跑起来时候执行哪些命令,有哪些环境变量设置等等。
如何使用ECS部署
接下来会介绍如何基于Application Load Balancer和ECS来部署自己的application
1. 打包docker image并push到ECR
我们从Dockerfile来打包一个demo的image:
FROM nodejs:7.6.0
COPY . /source
COPY ./env/production.env /source/.env
WORKDIR /source
RUN yarn install --production
EXPOSE 3000
CMD ["yarn", "start"]
执行 docker build -t 12345678.dkr.ecr.ap-northeast-1.amazonaws.com/demo:0.0.1 .
来打包image
成功后push到ECR中
$ aws ecr get-login --region ap-southeast-1
$ docker push 12345678.dkr.ecr.ap-northeast-1.amazonaws.com/demo:0.0.1
可以自己写个shell脚本把这些都自动化起来
2. 使用CloudFormation建立一个Application Load Balancer
可以参考AWS CF模板中ALB部分来写,主要是有AWS::ElasticLoadBalancingV2::LoadBalancer, AWS::ElasticLoadBalancingV2::Listener,AWS::ElasticLoadBalancingV2::TargetGroup这些资源,参考这个demo模板
3. 利用CloudFormation 来建立一个cluster
Cluster就是一组运行的EC2 instance,它需要在autoscaling组里面来管理保证cluster是可以随时扩展,所有这部分模板中应该保证有LaunchConfiguration, Cluster,Role,SecurityGroup参考这个demo的模板
4. 建立一个ECS service
有了cluster之后,我们就可以利用service把容器任务运行起来了,这里我们再建一个CF模板来创建service的资源,
要想用service来管理容器任务,首先定义一个task,在TD里面我们定义了一个container,它有name,cpu,memoery等一些基本属性,注意这里的PortMappings,我们把HostPort设置为0(或者也可以不设置),这里是为了使用动态端口映射,这样当这个container运行起来之后,ECS会给它随机分配一个主机端口,目前范围是从32768~61000,这样我们就可以在一个instance上同时跑多个container了,具体可以参考这里的portMappings中对hostPort的说明.
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: !Join ['-', [!Ref 'ServiceName', !Ref 'BuildNumber']]
Cpu: 512
Essential: 'true'
Memory: 512
PortMappings:
- HostPort: 0
Protocol: tcp
ContainerPort: !Ref 'ContainerPort'
Image: !Join [':', [!Join ['/', [!Ref 'ECR', !Ref 'ServiceName']], !Ref 'BuildNumber']]
然后我们就可以创建一个service来使用这个task definition,这个service会关联到之前创建的LoadBalancer中,我们使用的是Application Load Balancer,需要在这里指定它关联的TargetGroupArn,这样当容器任务跑起来之后,service会把它注册到这个targetGroup下面。
ECSService:
Type: AWS::ECS::Service
Properties:
Cluster:
Ref: ECSCluster
DesiredCount:
Ref: DesiredCount
LoadBalancers:
- ContainerName: !Join ['-', [!Ref 'ServiceName', !Ref 'BuildNumber']]
ContainerPort: 3000
TargetGroupArn:
Ref: TargetGroup
DeploymentConfiguration:
MaximumPercent: '200'
MinimumHealthyPercent: '50'
TaskDefinition:
Ref: TaskDefinition
Role:
Ref: ECSRole
当这三个CF创建的资源全都成功后,你的application就已经在容器中运行了,你可以通过ALB的地址来访问它。
5. 部署新版本
当有新的提交之后,我们会有新的版本,就会打包新的image并push到ECR中,这个时候只需要把service中的BuildNumber修改为新版本,然后update这个Stack,service会自动创建新的TaskDefinition并运行起来,然后把老的Task从targetGroup中去掉,这里会有一个draining时间,默认5分钟,MinimumHealthyPercent
参数指定了在部署过程中原来的版本最小百分比,保证在部署过程中业务不会中断,这样就完成了新旧版本的替换。
自动扩展
上面我们的application已经可以运行在ECS服务中了,但是还没有任何自动扩展功能,当遇到很大的访问量时候就会有问题了,我们需要添加自动扩展,在ECS中自动扩展包括两部分
Cluster 扩展
Cluster扩展主要是通过EC2的autoScalingGroup来完成的,我们定义了ASG,scale up和scale down的policy,以及触发这些policy的alarm就可以完成了。
Service 扩展
service的扩展我们需要建立ServiceScalingTarget,它指定了最小和最大的capacity,以及哪个service扩展
ServiceScalingTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: ECSService
Properties:
MaxCapacity: !Ref 'ServiceMaxASG'
MinCapacity: !Ref 'ServiceMinASG'
ResourceId: !Join ['', [service/, !Ref 'ECSCluster', /, !GetAtt [ECSService, Name]]]
RoleARN: !GetAtt [ECSAutoscalingRole, Arn]
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
然后需要创建scale up policy,与serviceScaleTarget关联起来,当需要scale up的时候,会触发这个policy,我们配置的AdjustmentType是ChangeInCapacity
同时stepAdjustments里面配置了ScalingAdjustment是1,即policy执行时候会增加一个容器任务做到横向service扩展,详细参考这里。
ServiceScalingUpPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: ScaleUpPolicy
PolicyType: StepScaling
ScalingTargetId: !Ref 'ServiceScalingTarget'
StepScalingPolicyConfiguration:
AdjustmentType: ChangeInCapacity
Cooldown: 300
MetricAggregationType: Average
StepAdjustments:
- MetricIntervalLowerBound: 0
ScalingAdjustment: 1
需要一个alarm来触发这个sale up policy,通过cloudWatch中AWS/ECS 命名空间下面的以ServiceName为维度的指标来触发,当CPU占用率在5分钟内大于60%即上报告警,触发scale up操作。
ECSCPUHighAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
EvaluationPeriods: 5
Statistic: Average
Threshold: 60
AlarmDescription: Alarm if CPU utilization if great than 60
Period: 60
AlarmActions:
- Ref: ServiceScalingUpPolicy
Namespace: AWS/ECS
Dimensions:
- Name: ServiceName
Value:
Ref: ECSService
ComparisonOperator: GreaterThanThreshold
MetricName: CPUUtilization
以上即是在AWS上使用ECS部署应用程序,并配置自动扩展策略的最简单实践。上面3个CloudFormation的模板可以参考这里
参考:
https://aws.amazon.com/blogs/compute/automatic-scaling-with-amazon-ecs/