我正在 EC2 服务上构建 ECS。我想实现蓝/绿部署,每次部署应用程序的新版本时,ECS 都会暂时将托管新版本的任务量加倍,并在新版本启动并运行后终止旧版本。
这是一种非常常见的应用程序部署方式,可确保用户不会停机。
正如我读过的AWS博客所建议的,我已经使用容量提供商创建了这个。所以我的 cdk 项目有以下结构
const autoscalingGroup = new AutoScalingGroup(this, `${this.id}-autoscaling-group`, {
maxCapacity: 2,
minCapacity: 1,
minHealthyPercentage: 100,
maxHealthyPercentage: 200,
desiredCapacity: 1,
...
})
capacityProvider = new AsgCapacityProvider(this, `${this.id}-capacity-provider`, {
autoScalingGroup: autoscalingGroup,
enableManagedScaling: true,
enableManagedTerminationProtection: true,
})
cluster = new Cluster(this, `${this.id}-ecs-cluster`, {
...
})
cluster.addAsgCapacityProvider(capacityProvider)
new Ec2Service(this, `${this.id}-ec2-service`, {
cluster: ecsCluster,
...
})
此 CDK 代码有效地创建了两个基础设施并将它们相互连接。
ECS 集群和服务负责为我的应用程序启动新任务,ASG 负责为我的应用程序任务启动服务器。 (Fargate 可以消除担心第二层的需要,但这不是重点)。
最后,这还会创建一个容量提供程序并将其分配给集群,以便集群知道在哪里为其 ECS 服务找到 EC2 实例。
在我的第一次部署中,一切都工作得很好——ASG 启动一个新的 EC2 实例,ECS 启动一个任务并放置在它上面。
任何后续部署都会出现此问题。此时,我希望 ECS 告诉 ASG 再扩展一个实例以适应另一项任务(在我的设置中,每个实例适合 1 个任务)。但这并没有发生,ECS 仍然陷入困境,无法找到有效的实例来放置新任务。
上述设置的问题在于它缺少一个关键组件; ECS 服务和容量提供商之间的纽带:
new Ec2Service(this, `${this.id}-ec2-service`, {
cluster: ecsCluster,
taskDefinition: this.props.taskDefinition,
// it's important to link this specific ECS service to the capacity provider.
// only linking the cluster doesn't allow this service to trigger ASG events
capacityProviderStrategies: [{
capacityProvider: capacityProvider.capacityProviderName,
weight: 1,
base: 1
}]
})
事实上,虽然让集群访问容量提供程序允许其服务在实例上放置任务,但它不允许单个服务触发向上和向下扩展。为此,您需要通过添加容量提供程序策略来告诉 ECSService 本身要使用哪个容量提供程序。有关策略具体设置的更多信息,请参见此处