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

时间:2016-10-09 22:36:24

标签: amazon-web-services amazon-ecs terraform

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

我正在使用Terraform进行AWS基础架构部署。

2 个答案:

答案 0 :(得分:5)

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

  1. 将您的更改改为user_data
  2. 运行terraform apply
  3. 对于ASG中具有旧user_data的每个EC2实例:
    1. 终止该EC2实例。您可以通过AWS CLI或EC2 Web控制台执行此操作。
    2. 过了一会儿,ASG会自动启动一个新的EC2实例,用新的user_data代替已终止的EC2实例。
    3. 过了一会儿,ECS会自动启动碰巧在已终止的EC2实例上运行的任何ECS任务的新副本。
  4. 完成此过程后,ASG中的所有实例都将运行新的user_data。请注意,只要符合以下条件,就可以使用ECS任务的零停机时间来完成此操作:

    1. 每个ECS任务至少有2个副本,每个副本位于ASG的单独EC2实例中。
    2. 您在终止EC2任务的EC2实例之间等待足够的时间重新启动。
    3. 如果您无法满足这些要求,那么您可能会遇到一些停机时间,或者您可能需要寻求一个更加混乱的选项,其中包括将ASG的大小加倍,等待新的EC2实例(将具有新的user_data)在ASG中部署,将ECS任务的数量增加一倍,等待部署新的ECS任务(它们通常将部署到新的EC2实例上),然后再将每个任务减少一半(理论上) ,旧的ECS任务和旧的EC2实例将被终止,只留下新的EC2实例。

答案 1 :(得分:1)

虽然Yevgeniy' answer是正确的,但是如果重新创建实例,则无法让Terraform直接将容器迁移到新实例。使用Terraform的资源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' s launch configuration docs

现在,当启动配置发生更改时,例如,如果用户数据或正在使用的AMI发生更改,这将强制Terraform创建新的启动配置,这会因为依赖于名称而强制启动新的自动扩展组

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

不幸的是,只显示EC2实例健康状况,而不是它成功运行任务。正如对此答案的评论中所提到的,ECS不会将任务自动平衡到集群中的新实例,因此Terraform将在旧的ASG中销毁运行ECS任务的实例,然后ECS可以将它们重新安排到新的ASG上造成停电的情况。

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

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

如果您的ECS任务已注册到负载均衡器,则一旦运行一组新任务,ECS将从负载均衡器取消注册任务,然后任务将在负载均衡器连接期间保留排水超时期限。