首页 > 解决方案 > 创建灵活的 terraform 模块以自定义可选参数时

问题描述

我想将几个资源放在一个 terrafrom 模块中。其中一个资源aws_ecs_service有一些可选参数,我可能需要也可能不需要,我想在调用模块时传递值。

例如考虑ordered_placement_strategy论点。一个服务可以有一个或多个ordered_placement_strategy。有些服务可能有也可能没有placement_constraints。如何为 aws_ecs_service 编写灵活的通用模块。

resource "aws_ecs_service" "mongo" {
  name            = "mongodb"
  cluster         = aws_ecs_cluster.foo.id
  task_definition = aws_ecs_task_definition.mongo.arn
  desired_count   = 3
  iam_role        = aws_iam_role.foo.arn
  depends_on      = [aws_iam_role_policy.foo]

  ordered_placement_strategy {
    type  = "binpack"
    field = "cpu"
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.foo.arn
    container_name   = "mongo"
    container_port   = 8080
  }

  placement_constraints {
    type       = "memberOf"
    expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"
  }
}

标签: terraformterraform-provider-aws

解决方案


看起来像是locals + dynamic blocks的可靠用例。

如果您已经了解模块中应支持的任务放置策略,这将有所帮助。您可以向最终用户公开输入变量,并使用它来相应地创建服务。

例如:假设我们要支持两种服务:

  • 简单的
  • 复杂的

我会首先定义一个带有这样验证的输入变量,以避免未知数:

variable "ecs_service_type" {
  type        = string
  description = "What kind of service is this?"

  validation {
    condition     = can(regex("^(simple|complex)$", var.ecs_service_type))
    error_message = "The service type must be in (simple|complex)."
  }
}

您可以使用以下本地值定义支持的任务放置策略和约束:

locals {
  ordered_placement_strategy = {
    simple = [
      {
        "field" : "instanceId",
        "type" : "spread"
      }
    ]
    complex = [
      {
        type  = "spread"
        field = "attribute:ecs.availability-zone"
      },
      {
        type  = "spread"
        field = "instanceId"
      }
    ]
  }

  placement_constraints = {
    simple = []

    complex = [
      {
        type = "distinctInstance"
      }
    ]
  }

}

最后,使用动态块相应地创建服务:

resource "aws_ecs_service" "service" {
  ...
  ...

  dynamic "ordered_placement_strategy" {
    for_each = local.ordered_placement_strategy[var.ecs_service_type]

    content {
      type  = ordered_placement_strategy.value.type
      field = ordered_placement_strategy.value.field
    }
  }

  dynamic "placement_constraints" {
    for_each = local.placement_constraints[var.ecs_service_type]

    content {
      type = placement_constraints.value.type
    }
  }
}

PS:这段特定的代码没有经过测试,但我使用了类似的方法。如果您需要任何帮助,请告诉我。


推荐阅读