【问题标题】:How can I split up resource creation into different modules with Terraform?如何使用 Terraform 将资源创建拆分为不同的模块?
【发布时间】:2019-06-25 20:17:19
【问题描述】:

我想使用不同的模块来拆分资源创建,但我一直无法弄清楚如何。

对于此示例,我想创建一个 Web 应用程序(我正在使用 azurerm 提供程序)。我通过将以下内容添加到模块中来做到这一点:

resource "azurerm_app_service" "test" {
  name                = "${var.app_service_name}"
  location            = "${var.location}"
  resource_group_name = "${var.resource_group_name}"
  app_service_plan_id = "${var.app_service_plan_id}"

  app_settings {
    SOME_SETTING = "${var.app_setting}"
  }
}

它可以工作,但我想有一个单独的模块来应用应用程序设置,所以:

  • 模块 1 创建网络应用程序
  • 模块 2 应用应用设置
  • 潜在模块 3 将其他内容应用于 Web 应用程序

这可能吗?我尝试将其拆分(有两个模块定义 Web 应用程序,但其中只有一个包含应用程序设置),但我收到一条错误消息,指出 Web 应用程序已经存在,所以它似乎不明白我试图操作相同的资源。

详细说明如何使用: 我将为最终用户提供一个 UI,他/她可以在该 UI 上选择所需的一堆资源并勾选该人的项目所需的一系列选项,以及填写基础设施所需的参数。

完成并提交后,参数将应用于 Terraform 模板。为每个选项排列设置一个模板是不可行的,因此必须根据所选选项包含不同的模块。

例如:如果用户勾选 Web 应用程序、Cosmos DB 和应用程序洞察,Terraform 模板将包含这些模块(使用计数技巧创建条件)。在此示例中,我需要将检测密钥从应用程序洞察传递到 Web 应用程序的应用程序设置,这就是我的问题所在。

如果用户没有选择应用程序洞察力,我不想要 Web 应用程序的设置,这就是我需要逐步构建 Terraform 资源的原因。此外,根据用户选择的数据库类型,Web 应用的设置中会添加不同的设置。

所以我的想法是创建一个模块来应用某些应用程序设置。我不知道这是否可能(或存在更好的方法),因此我的问题。

【问题讨论】:

  • 为什么要这样做?您能否提供一个更完整/具体的示例来说明您在此处尝试实现的目标?
  • 当然。我正在创建一些不同消费者将使用的通用模板。他们的要求可能略有不同。也许一个人根本不需要应用程序设置,而另一个人确实需要它,或者一个人可能需要 SQL 服务器,因此需要一组额外的设置。另一个例子是 WAF,其中一个消费者可能对某些规则排除感兴趣,因此需要为此目的配置一个配置块,而另一个消费者可能不需要。
  • 这个过程将是自动化的,所以我不会为每个消费者手动更改模板。这就是为什么根据消费者选择的功能逐步建立资源会很好的原因。
  • 如果您可以编辑您的问题以显示不同的人希望如何使用该模块,这将有所帮助。
  • @ydaetskcoR 我已将用例添加到问题的底部。我希望这足以理解为什么我需要能够做到这一点。

标签: terraform terraform-provider-azure


【解决方案1】:

执行此操作的最佳方法是使用 bash 脚本或您想要的任何脚本语言 (python) 包装 terraform。然后在 bash 或 python (jinja2) 中创建一个模板,以使用客户为设置选择的任何选项生成资源,运行模板以生成您的 terraform 代码,然后应用它。

我已经用 S3 存储桶做了很多。在 terraform 0.12 中,您可以在 terraform 中生成模板。

【讨论】:

  • 感谢您的回答。假设这是否意味着目前无法单独使用 Terraform 来实现?我在 0.12 中阅读了一些有关模板的信息,并试用了预览版。我不确定我是否能够使用模板实现我想要的。
  • 0.12 动态嵌套块据说可以实现相同的hashicorp.com/blog/…
  • 我不太确定动态块如何解决我想要实现的目标。会不会是一堆串联的列表,混杂了各种条件?
  • 好吧,您可以将设置传递到 terraform,并使用动态块,您可以查看它们以创建 app_settings 块,为每个客户定制。您甚至可以将设置作为 JSON 传递并使用 data.external 解析它们
  • 我为迟到的回复道歉。我不确定它会不会像我想要的那样工作。我认为不可能使用动态块构建应用程序设置,但我必须定义整个应用程序设置映射,因为应用程序设置本身就是一个块。我在预览中尝试了一些尝试组合动态块和循环(使用它们提供的示例),但也没有运气。也许我应该再试一次。
【解决方案2】:

我知道这是 5 个月大,但我认为这里的部分情况是您描述的拆分方式并不完全符合模块的预期使用方式。一方面,您不能动态地“构建资源”,因为 Terraform 是设计声明的。您只能定义一个资源,然后动态提供它的预定义输入(包括激活/停用的计数)。其次,模块绝不需要通过配置打开和关闭部分堆栈。模块只是将资源集组合在一起以进行包含和重用的一种方式。由复杂的模块层次结构组成的堆栈提供给您的任何动态都将在一个巨大的整体 blob 中使用基本相同的代码同样可用。单体应用会变得一团糟,这就是问题所在,而且你不能将它的一部分用于其他事情。最后,使用模块来提供设置并不是它们真正的用途。是的,理论上你可以创建一个带有“null_data_source”的模块,然后将它纯粹用作某种垫片来提供设置,但这可能是一种复杂的不必要的方法,通过简单地提供一个变量来完成更好的事情你有已经显示了。

您可能将需要将其包装在顶层的某种 bash (etc) 脚本中,如其他答案中所述,这 不是 terraform 的限制.例如,一旦您有了模块,您可能希望将所有当前应用的堆栈(针对每个客户或其他)保留在某种组合存储库中。在这些客户填写设置表格后,您将如何为他们创建组合堆栈?您将不得不通过一些文件创建自动化来做到这一点,这不是 Terraform 的用途。 Terraform 用于执行存在的堆栈。您必须首先使用外部文本编辑器创建 .tf 文件,这不是 Terraform 的限制,在这种情况下,您可以使用一些外部脚本为客户动态创建合成堆栈,这不是限制,这只是您使用自动化为 Terraform 做好应用堆栈工作的一部分方式。

因此,您无法避免使用这种外部脚本工具,您可能会使用它来为客户特定的组合堆栈(引用您的模块)创建文件夹,使用默认文件填充文件夹,并创建一个 .tfvars根据客户从表格中输入的文件。然后你可以通过多种方式进行:

  1. 您将 .tfvars 文件作为客户组合堆栈之间的唯一区别。给定来自 .tfvars 的变量,您使用或不想使用的任何模块都将被您提到的“计数技巧”激活/停用。这种方式的优点是易于推理,因为所有客户组合堆栈都是相同的,只是配置不同。

  2. 您可以让工具将您想要的模块定义实际插入到组合堆栈的文件中。这将创建更简洁的组合堆栈,更少的“计数技巧”乱七八糟,但每个客户的堆栈都将是它自己的怪异雪花。

就模块的拆分而言,请注意,这涉及到一整套艺术/科学/哲学。我将您推荐给this resource on IAC design patterns 和this talk on the subject(相关位从19:15 开始)。这些是该主题的一般背景。

对于您的特定情况,您基本上希望将所有最小的可分割功能块(可能打开/关闭)放入它们自己的模块中,每个模块都由更高级别的消耗模块引用。您提到为每个排列都设置一个模块是不可行的,这又是错误的考虑。您的目标是更多的模块和组合的树。在顶层,您将拥有(bash 等)工具来创建新的客户组合文件夹、他们的 .tfvars 文件,并放入将成为“模块树”顶部的相同组合堆栈。代表客户堆栈的可选部分的每个模块都将进行计数。这些模块要么内部有功能资源,要么是中间模块,它们自己实例化一组可配置的包含资源的替代子模块。

但您可以坐下来仔细考虑“决策树”的设计,该决策树被实现为模块的层次结构,它涵盖了无法为其创建单独的整体堆栈的所有排列。

TFv12 动态嵌套块将在拥有或不拥有像 app_settings 这样的声明块这一方面为您提供特别帮助。由于您不能动态地“构建资源”,因此在这种情况下,唯一的选择是拥有一个以多种方式声明资源的中间模块(有和没有 app_settings 块),并且将通过“计数”选择一个技巧”或其他输入配置。既然存在动态块,这种事情就没有必要了。

【讨论】:

    猜你喜欢
    • 2019-03-19
    • 1970-01-01
    • 2022-09-22
    • 2019-08-26
    • 2023-02-23
    • 2019-10-31
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多