我有以下Terraform代码来更新具有新任务定义的服务:
resource "aws_ecs_task_definition" "app_definition" {
family = "my-family"
container_definitions = "${data.template_file.task_definition.rendered}"
network_mode = "bridge"
}
resource "aws_ecs_service" "app_service" {
name = "my-service"
cluster = "my-cluster"
task_definition = "${aws_ecs_task_definition.app_definition.arn}"
desired_count = "1"
iam_role = "my-iam-role"
}
更新我的服务时,我的任务定义的最新修订版变为非活动状态。因此,在尝试手动回滚到ECS控制台中的先前版本时,我无法选择它:
Error: No active task definition found
理想情况下,我想保持最后的X版本处于活动状态,因此如果出现问题,我总是可以通过控制台手动回滚。
我怎样才能做到这一点?
Terraform目前不允许这样做,它的资源生命周期模型意味着当你替换某些东西(任务定义是不可变的)时,Terraform必须创建一个新的并销毁旧的。
使用ECS时,任务定义也无法真正被销毁,而只是被标记为非活动状态,因为当前部署的任务可能正在使用它,直到服务更新为新任务定义。
有两种常见的方法可以解决这个问题,并且需要能够回滚到以前版本的任务定义。
第一种方法是在初始创建之后不使用Terraform来管理任务定义,而是使用AWS ECS CLI工具来代替。
另一个选项,也就是我使用的选项,是让我的CI(在我们的例子中是Gitlab CI)生成一个用要部署的应用程序的提交SHA标记的Docker镜像,然后Terraform将任务定义更新为新的提交SHA在apply
上标记图像,以及使用新任务定义ARN更新ECS服务。
当我们想要回滚时,我们使用CI的能力回滚到不同的提交,只使用旧提交SHA启动部署作业,然后部署旧映像。
这使得Terraform对所部署的内容非常不了解,并使CI系统负责部署所需的版本,这通常是最新的,但有时是特定的提交,如果我们有一个手动点击部署,当然还有回滚时的目标先前版本。
这确实意味着您无法通过AWS控制台启动回滚,但我实际上喜欢这样,因为我希望CI系统随时可以成为部署内容的真相来源。
一个非常简单的方法是挂钩Terraform的生命周期:
resource "aws_ecs_task_definition" "app_definition" {
family = "my-family"
container_definitions = "${data.template_file.task_definition.rendered}"
network_mode = "bridge"
# make sure Terraform does not unregister the task definition
lifecycle {
prevent_destroy = true
}
}
As discussed in this Pull Request它可以防止破坏旧的任务定义,从而使所有任务定义保持活动状态。