AWS ECS:使用单容器主机自动扩展 EC2 Auto-Scaling 组

Jor*_*dan 3 amazon-ec2 amazon-web-services amazon-ecs autoscaling terraform

我有一个相当有趣的情况,我正在尝试弄清楚如何在 AWS ECS/EC2 上进行配置。

我有一个 Dockerized 应用程序,具有以下要求:

  • CPU 使用率极低(~256 个 CPU)
  • 中等内存使用量(~256 MB)
  • 每个容器都需要一个仅分配给该容器的公共 IP 地址(不与任何其他容器共享)。

由于成本原因,Fargate 不是一个选择,因此我们正在考虑基于 EC2 的解决方案。

由于 CPU 和内存使用率较低,并且我需要为每个容器提供唯一的公共 IP 地址,因此 ECS 容量提供商的最佳选择似乎是使用最小实例( 、 等)的 EC2 自动缩放组t4g.nanot3a.nano并且或host网络bridge模式(如果我明确指定静态主机/容器端口映射,则任一模式都将限制为每个主机一个容器)。这为我提供了主机到容器的一对一映射,这正是我所需要的。

问题是,如何为此设置 ECS 集群管理的自动缩放?

我已经配置了 EC2 自动缩放组 (Terraform):

resource "aws_autoscaling_group" "ecs" {
  name                = "ecs"
  vpc_zone_identifier = var.subnet_ids
  min_size            = 1
  max_size            = 20
  capacity_rebalance  = true
  default_cooldown    = 0
  health_check_type   = "EC2"
  mixed_instances_policy {
    ...
  }
  instance_refresh {
    strategy = "Rolling"
  }
}
Run Code Online (Sandbox Code Playgroud)

我已将自动扩展组配置为具有托管扩展功能的 ECS 容量提供商:

resource "aws_ecs_capacity_provider" "ec2" {
  name = "ec2"
  auto_scaling_group_provider {
    auto_scaling_group_arn = aws_autoscaling_group.ecs.arn
    managed_scaling {
      target_capacity           = 100
      instance_warmup_period    = 30
      minimum_scaling_step_size = 1
      maximum_scaling_step_size = aws_autoscaling_group.ecs.max_size
      status                    = "ENABLED"
    }
    managed_termination_protection = "DISABLED"
  }
}
Run Code Online (Sandbox Code Playgroud)

我已将此容量提供程序配置为 ECS 集群的唯一提供程序:

resource "aws_ecs_cluster_capacity_providers" "this" {
  cluster_name = aws_ecs_cluster.this.name
  capacity_providers = [
    aws_ecs_capacity_provider.ec2.name
  ]
  default_capacity_provider_strategy {
    capacity_provider = aws_ecs_capacity_provider.ec2.name
    weight            = 100
    base              = 0
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经设置了 ECS 服务:

resource "aws_ecs_service" "this" {
  name            = local.task_family
  cluster         = aws_ecs_cluster.this.id
  task_definition = aws_ecs_task_definition.this.arn
  desired_count   = 1
  launch_type     = "EC2"
  lifecycle {
    ignore_changes = [desired_count]
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经为 ECS 服务设置了应用程序自动缩放目标:

resource "aws_appautoscaling_target" "ecs" {
  min_capacity       = 5
  max_capacity       = 20
  resource_id        = "service/${aws_ecs_cluster.this.name}/${aws_ecs_service.this.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}
Run Code Online (Sandbox Code Playgroud)

我已经为该目标设置了应用程序自动缩放策略:

resource "aws_appautoscaling_policy" "ecs_policy" {
  name               = "ecs-scaling"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs.service_namespace

  target_tracking_scaling_policy_configuration {
    target_value       = 70
    scale_in_cooldown  = 0
    scale_out_cooldown = 0
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这“有效”是指它已部署、服务正在运行并且我的应用程序可以正常运行。但是,缩放不起作用。正如您在 中所看到的aws_autoscaling_group,我已将最小值设置为 1 个实例,将最大值设置为 20 个实例。在 中aws_appautoscaling_target,我最少有 5 个(在生产中为 1 个,但在测试中为 5 个),最多为 20 个(最大值与最大实例数匹配,因为它是 1 对 1)。

当我部署此服务时,AWS 控制台中的 ECS 服务显示:

  • 所需数量:5
  • 待处理数:0
  • 运行次数:1

在事件日志中,它说:

服务 my-service 无法放置任务,因为没有容器实例满足其所有要求。最接近的匹配容器实例 xyzabc1234 没有足够的可用内存。

因此,它正在尝试实现所需的最小容器数量 (5),并且它认识到 EC2 实例不足,但由于某种原因(这是我无法弄清楚的原因),它没有扩展 EC2 实例的数量以满足所需的集装箱数量。

AWS 的文档来看,它说:

当启动的任务无法放置在可用实例上时,Auto Scaling 组会通过启动新实例进行横向扩展。当存在正在运行但没有任务的实例时,Auto Scaling 组会通过终止没有正在运行的任务的实例来进行缩减。

由于启动的任务不能放置在任何可用实例上,因此它似乎应该自动扩展 Auto Scaling 组。

关于为什么它失败的任何想法?

Jor*_*dan 6

我发现了这个问题:

resource "aws_ecs_service" "this" {
...
  launch_type     = "EC2"
...
}
Run Code Online (Sandbox Code Playgroud)

如果您指定启动类型,它将覆盖集群的默认容量提供程序策略,并且不会使用托管 EC2 自动扩展。正确的做法是:

resource "aws_ecs_service" "this" {
  name            = local.task_family
  cluster         = aws_ecs_cluster.this.id
  task_definition = aws_ecs_task_definition.this.arn
  desired_count   = 1

  capacity_provider_strategy {
    capacity_provider = aws_ecs_capacity_provider.ec2.name
    weight            = 100
    base              = 0
  }

  lifecycle {
    ignore_changes = [desired_count]
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您不提供launch_typeor capacity_provider_strategy,它应该使用集群的默认策略(确实如此),但 Terraform 显示出永久的差异。

进行此更改后,一切都开始正常扩展!