当ECS中有多个仅在命令上有所不同的服务时,如何避免在Terraform中重复?

时间:2019-03-01 12:24:36

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

我们通过定义template_file在Terraform中创建ECS服务,该文件使用所有需要的变量填充任务定义JSON模板。然后,使用渲染的template_file创建一个aws_ecs_task_definition。使用此任务定义创建了aws_ecs_service

data "template_file" "web" {
  template = "${file("${path.module}/tasks/web.json")}"

  vars {
    ...
  }
}

resource "aws_ecs_task_definition" "web" {
  container_definitions    = "${data.template_file.web.rendered}"
  requires_compatibilities = ["FARGATE"]
  ...
}

data "aws_ecs_task_definition" "web" {
  task_definition = "${aws_ecs_task_definition.web.family}"
}

resource "aws_ecs_service" "web" {
  name            = "web"
  task_definition = "${aws_ecs_task_definition.web.family}:${max("${aws_ecs_task_definition.web.revision}", "${data.aws_ecs_task_definition.web.revision}")}"
  ...
}

还有一些其他服务,它们的任务定义几乎与第一个相同,只是与另一个命令的区别很小(例如,启动sidekiq而不是Web应用程序)。

除了复制所有内容(JSON模板template_file和所有定义的变量aws_ecs_task_definitionaws_ecs_service)之外,还有其他方法吗?

2 个答案:

答案 0 :(得分:0)

Modules是在Terraform中解决此问题的主要方法。

如果将现有代码移动到单个文件夹中,则可以定义允许您自定义该模块的变量,例如要传递给ECS服务的命令。

因此,在您的情况下,您可能会遇到类似这样的情况:

modules / foo-service / main.tf

data "template_file" "web" {
  template = "${file("${path.module}/tasks/web.json")}"

  vars {
    # ...
    command = "${var.command}"
  }
}

resource "aws_ecs_task_definition" "web" {
  container_definitions    = "${data.template_file.web.rendered}"
  requires_compatibilities = ["FARGATE"]
  # ...
}

data "aws_ecs_task_definition" "web" {
  task_definition = "${aws_ecs_task_definition.web.family}"
}

resource "aws_ecs_service" "web" {
  name            = "web"
  task_definition = "${aws_ecs_task_definition.web.family}:${max("${aws_ecs_task_definition.web.revision}", "${data.aws_ecs_task_definition.web.revision}")}"
  # ...
}

modules / foo-service / variables.tf

variable "command" {}

staging / main.tf

module "foo_service_web" {
  source  = "../modules/foo-service"
  command = "bundle exec server"
}

module "foo_service_sidekiq" {
  source  = "../modules/foo-service"
  command = "bundle exec sidekiq"
}

答案 1 :(得分:0)

扩展接受的答案,以显示如何还消除由template_file vars块中的已定义变量引起的重复(该重复不会改变,因此在模块调用之间必须重复)。这也不是仅内联这些变量或使用默认值的解决方案,因为它们仍将在项目之间更改,只是不在同一项目的服务中更改。我们可以使用局部变量来设置默认值,并使用合并功能覆盖默认值:

main.tf

locals {
  task_variables = {
    image = "..."
    # lots of other variables
    command = "[\"nginx\", \"-g\", \"daemon off; error_log /dev/stdout info;\"]"
  }
}

# first invocation of the module, overriding the command
module "sidekiq" {
  source = "ecs_service"
  ...
  task_variables = "${merge(
    local.task_variables,
    map(
      "command", "[\"bash\", \"-c\", \"exec bundle exec sidekiq\"]",
    )
  )}"
}

# second invocation of the module, no overrides
module "web" {
  source = "ecs_service"
  task_variables = "${local.task_variables}"
}

模块ecs_service

variable "task_variables" {
  type = "map"
}

data "template_file" "web_task" {
  template = "${file("${path.module}/tasks/task_definition.json")}"

  vars = "${var.task_variables}"
}

resource "aws_ecs_task_definition" "web" {
  container_definitions    = "${data.template_file.web_task.rendered}"
  ...
}

data "aws_ecs_task_definition" "web" {
  task_definition = "${aws_ecs_task_definition.web.family}"
  ...
}

resource "aws_ecs_service" "web" {
  task_definition = "${aws_ecs_task_definition.web.family}:${max("${aws_ecs_task_definition.web.revision}", "${data.aws_ecs_task_definition.web.revision}")}"
  ...
}