Terraform : for_each 一个一个

Posted

技术标签:

【中文标题】Terraform : for_each 一个一个【英文标题】:Terraform : for_each one by one 【发布时间】:2021-12-31 02:36:14 【问题描述】:

我在 terraform 上创建了一个模块,该模块创建 aws_servicecatalog_provisioned_product 资源。 当我从根目录调用此模块时,我使用 for_each 来运行对象列表。 该模块运行到此对象列表中并并行创建 aws_servicecatalog_provisioned_product 资源。 有没有办法一个一个地创建资源?我希望该模块将等待第一次迭代完成并在之后创建下一次迭代。

【问题讨论】:

进展如何?仍然不清楚你能做什么? 我正在使用 jinja 模板,它使用 depons_on 创建多个资源到前一个资源。 @DaniWol.- 你能分享一个解决方案吗 - 我目前正在处理类似的情况 @MichałDygas 我正在使用 terraform templatefiledepends on 顺序创建资源,然后 terraform 一个一个地创建资源。 @DaniWol。我理解这个概念,但坦率地说,我对实现细节很好奇。我已经尝试过在初始应用期间生成本地文件的方法。在第二次申请期间创建了资源。不幸的是,这是一种流行的方法——主要是缺乏自动化部分。那么我可以再请你分享一个sn-p吗? 【参考方案1】:

有没有办法一一创建资源?

遗憾的是,没有这样的方法,除非您删除 for_each 并使用 depends_on 分别创建所有模块。

TF 不是一种过程语言,它总是会为for_eachcount 并行处理。

【讨论】:

【参考方案2】:

如果您想确保一个接一个地创建它们,您必须删除for_each 并为每个元素使用depends_on

如果您只想在其他资源之前配置第一个资源:

仅分离第一个资源,其余资源使用for_each。您可以使用depends_on 放置一个显式依赖项,以使剩余资源依赖于第一个资源。因为for_each 需要setmap,所以此输入需要进行一些修改才能排除第一个资源的配置。

如果你真的需要一个一个配置资源,一个更激进的方法是运行apply 命令和-parallelism=1。这会将并行供应的资源数量减少到 1。这将适用于整个项目。我不建议这样做,因为它会大大增加应用程序的运行时间。

【讨论】:

并行会影响所有资源,对我不利。我需要一个一个地配置资源,但不是将并行性应用于所有资源。【参考方案3】:

为什么要它等待上一次创建? Terraform 依靠提供者知道可以并行发生的事情,并将在可能的情况下并行运行。

如果我愿意,在应用操作之前设置并行度将是我限制它的人为方式,因为它是一种技术解决方法,可让您的 Terraform 代码易于阅读。

TF_CLI_ARGS_apply="-parallelism=1"
terraform apply

如果您发现这会减慢所有 Terraform 创建的速度,但您需要一次部署一个特定资源集,那么可能是时候将这些特定资源分解到它们自己的 Terraform 配置目录中并将其应用到使用并行设置再次对其余资源执行不同的步骤。

【讨论】:

当我创建 aws_servicecatalog_provisioned_product 时,其中一个资源已成功创建,另一个得到以下错误:ResourceInUseException Account Factory cannot create this enrolled account right now, because another execution is in progress. Try again later. 当我从控制台创建资源时,我得到同样的错误,并行性会影响所有资源,对我不利。 听起来像是提供者 @DaniWol 中的一个错误。 @DaniWol,我的建议再次是拆分此资源的目录。或者,您可以在提供者 Github 页面上提出问题,甚至提供修复。这是一个示例,其中有人针对 EKS Fargate 的相同问题执行此操作。提出的问题:github.com/hashicorp/terraform-provider-aws/issues/13372 贡献:github.com/hashicorp/terraform-provider-aws/pull/14020【参考方案4】:

我正在使用 terraform templatefiledepends on 的顺序创建资源,然后 terraform 一个一个地创建资源。

代码如下:

locals 

     expanded_accounts = [ 
      
          AccountEmail                           = example1@example.com
          AccountName                         = example1
          ManagedOrganizationalUnit           = example_ou1
          SSOUserEmail                        = example1@example.com
          SSOUserFirstName                    = Daniel
          SSOUserLastName                     = Wor
          ou_id                               = ou_id1
      ,
      
          AccountEmail                           = example2@example.com
          AccountName                         = example2
          ManagedOrganizationalUnit           = example_ou2
          SSOUserEmail                        = example2@example.com
          SSOUserFirstName                    = Ben
          SSOUserLastName                     = John
          ou_id                               = ou_id2
     
     ]

  previous_resource = [
    for acc in local.expanded_accounts :
    acc.AccountName
  ]

     resources =  res = local.expanded_accounts, previous = concat([""], local.previous_resource)


resource "local_file" "this" 
  content              = templatefile("./provisioned_accounts.tpl", local.resources)
  filename             = "./generated_provisioned_accounts.tf"
  directory_permission = "0777"
  file_permission      = "0777"

  lifecycle 
    ignore_changes = [directory_permission, file_permission, filename]
  

provisioned_accounts.tpl配置:

% for acc in res 
resource "aws_servicecatalog_provisioned_product" "$acc.AccountName" 
  name                     = "$acc.AccountName"
  product_id               = replace(data.local_file.product_name.content, "\n", "")
  provisioning_artifact_id = replace(data.local_file.pa_name.content, "\n", "")
  

  provisioning_parameters 
    key   = "SSOUserEmail"
    value = "$acc.SSOUserEmail"
  
  provisioning_parameters 
    key   = "AccountEmail"
    value = "$acc.AccountEmail"
  
  provisioning_parameters 
    key   = "AccountName"
    value = "$acc.AccountName"
  
  provisioning_parameters 
    key   = "ManagedOrganizationalUnit"
    value = "$acc.ManagedOrganizationalUnit ($acc.ou_id)"
  
  provisioning_parameters 
    key   = "SSOUserLastName"
    value = "$acc.SSOUserLastName"
  
  provisioning_parameters 
    key   = "SSOUserFirstName"
    value = "$acc.SSOUserFirstName"
  

  timeouts 
    create = "60m"
  

%if index != 0 
  depends_on = [aws_servicecatalog_provisioned_product.$previous[index]]
% endif 



%~ endfor ~

【讨论】:

以上是关于Terraform : for_each 一个一个的主要内容,如果未能解决你的问题,请参考以下文章

将 aws 资源导入具有 for_each 的 terraform 模块

Terraform 模块输出用作其他模块中的输入,特别是 for_each

如何在 terraform 中正确使用 for_each 中的 each.value?

Terraform 因 for_each 参数无效/给定的“for_each”参数值不合适而失败

Terraform For_Each:如何引用创建的资源 ID

具有来自 .tfvars 的值的 terraform for_each 实现