如何强制 AWS ECS 将容器迁移到另一个 ASG?

How to force AWS ECS migrate containers to another ASG?

我正在使用 user_data 将 ECS 中使用的主机初始配置到 运行 容器。我希望能够在我更新 user_data 后告诉 AWS ECS 将容器迁移到新创建的主机。我该怎么做?

我正在使用 Terraform 进行 AWS 基础设施部署。

我认为 ECS 没有内置的方法来执行此操作。因此,它通常需要一个相当繁琐的手动过程(尽管可以编写脚本)。有几种不同的方法可以做到这一点,但这通常是最简单的方法:

  1. user_data 进行更改。
  2. 运行 terraform apply.
  3. 对于您的 ASG 中每个具有旧 user_data 的 EC2 实例:
    1. 终止该 EC2 实例。您可以通过 AWS CLI 或 EC2 Web 控制台执行此操作。
    2. 稍后,ASG 将使用您的新 user_data 自动启动一个新的 EC2 实例,以替换已终止的 EC2 实例。
    3. 片刻之后,ECS 将自动启动恰好 运行 在终止的 EC2 实例上的任何 ECS 任务的新副本。

完成此过程后,ASG 中的所有实例都将 运行 成为新的 user_data。请注意,只要满足以下条件,您的 ECS 任务就可以在零停机时间的情况下完成:

  1. 每个 ECS 任务至少有 2 个副本,每个都在您的 ASG 中的一个单独的 EC2 实例上。
  2. 您在终止 EC2 实例之间等待足够的时间,以便 ECS 任务重新启动。

如果您不能满足这些要求,那么您可能会有一些停机时间,或者您可能需要采取更复杂的选择,包括将 ASG 的大小增加一倍,等待新的 EC2 实例(它将具有new user_data) 在 ASG 中部署,将 ECS 任务的数量加倍,等待部署这些新的 ECS 任务(它们通常会部署到新的 EC2 实例上),然后再次将每个任务减半(理论上,旧的 ECS 任务和旧的 EC2 实例将被终止,只留下新的)。

同时 Yevgeniy's is correct in that there's no way to get Terraform to directly migrate containers to new instances in the event the instances are recreated there is a much cleaner option available to you using Terraform's resource lifecycle configuration.

假设您正在使用自动缩放组来支持您的 ECS 主机,您可以这样做:

data "aws_ami" "ubuntu" {
  most_recent = true
  filter {
    name = "name"
    values = ["ubuntu/images/ebs/ubuntu-trusty-14.04-amd64-server-*"]
  }
  filter {
    name = "virtualization-type"
    values = ["paravirtual"]
  }
  owners = ["099720109477"] # Canonical
}

resource "aws_launch_configuration" "as_conf" {
  name_prefix = "terraform-lc-example-"
  image_id = "${data.aws_ami.ubuntu.id}"
  instance_type = "t1.micro"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "bar" {
  name = "${aws_launch_configuration.as_conf.name}"
  launch_configuration = "${aws_launch_configuration.as_conf.name}"

  lifecycle {
    create_before_destroy = true
  }
}

(取自 Terraform 的 launch configuration docs

现在,当启动配置发生变化时,例如,如果用户数据或正在使用的 AMI 发生变化,这将强制 Terraform 创建新的启动配置,由于依赖于名字。

由于 Terraform 使用 create_before_destroy 生命周期配置,它将在销毁它之前创建新的启动配置和 ASG。在上面的简单设置中,一旦单个实例被 AWS 认为健康,ASG 就会 return 完成。

不幸的是,它仅在 EC2 实例运行状况良好时显示,而不是在成功执行 运行 任务时显示。正如对此答案的评论中提到的,ECS 不会将任务自动平衡到集群中的新实例,因此 Terraform 然后会在 ECS 将它们重新安排到导致中断的新 ASG 实例。

要解决此问题(并且还允许实例失败并以更好的方式进行一般替换),您可以使用 ASG lifecycle hooks 在实例标记为终止时但在它被标记为终止之前执行一些操作实际终止。

确实有一个很好的 AWS blog post 这样做,并且有一些 [示例 Lambda 代码] 响应挂钩以在完成生命周期挂钩之前耗尽标记为终止的容器实例,这将允许ASG 终止实例。耗尽容器实例后,ECS 将自动将最少数量的健康任务重新安排到非耗尽实例(在新的 ASG 中)。

如果您的 ECS 任务已注册到负载均衡器,一旦一组新任务 运行 将被 ECS 从负载均衡器中注销,然后任务将在负载期间保留平衡器的连接耗尽超时时间。