Terraform null_resource 未与后端一起运行

tjd*_*bts 2 azure terraform

我有一个地形变量地图,如下所示

variable "MyProj" {
  type = map(object({
  name     = string
  type     = string
 }))
default = {
  "Proj1" = {
      name      = "Proj1"
      programme = "java"
   },
   "Proj2" = {
      name       = "Proj2"
      programme  = "npm"
  }
 }
}
Run Code Online (Sandbox Code Playgroud)

我还有一个空资源代码,只要根据上述映射(对象())和所需状态识别出更改,该代码就会运行批处理脚本。

   resource "null_resource" "nullr" {
   for_each = var.MyProj

   provisioner "local-exec" {
   command = "bash /home/myscript.sh ${each.value.name} ${each.value.progrmme}
  }
}
Run Code Online (Sandbox Code Playgroud)

我的意图是,每当在上面的 map() 中识别出更改时,就应该运行空资源。

当我将 terraform 状态保留在本地计算机中时,它会按预期运行。但是,当我使用 azurem 后端将 terraform 状态保留在 Azure blob 容器中时,它不会运行 null_resource。即使我使用 terraform 状态的后端,我也应该在配置中进行哪些更改

Mar*_*ins 5

我首先想说的是,您在这里所做的事情似乎超出了 Terraform 的典型范围:通常类似的工具npm属于构建/部署管道的“构建”步骤,而 Terraform 并不是真正的意图或设计处理该系列用例。由于它是一个通用的可编程工具,如果您有创造力,您当然可以让它做超出其范围的事情,但它通常带有警告和限制。

我将尝试在您编写问题时回答您的问题,但我还建议您更哲学地思考是否可以更好地使用在管道中的 Terraform 之前运行的单独进程来解决本打算解决的任何问题,或者,如果整个问题可以通过明确设计用于支持构建和部署流程的其他系统更好地解决。


资源null_resource类型是 Terraform 中的一个特殊的“逃生舱口”,它故意不执行任何操作,以便您可以将本来不属于资源的配置程序附加到它。配置程序的预期目的(尽管作为最后手段)是实现特定对象需要执行的附加步骤,以便完全可操作,例如将一些所需的数据写入虚拟机的文件系统。

普通资源类型具有由远程系统定义的固有规则,这些规则涉及哪些类型的更改可以就地应用以及哪些类型的更改需要重新创建对象。因为null_resource不代表特定的远程对象类型,所以它没有任何此类固有规则,但它确实有一个更人为的参数概念triggers,该参数除了在其值与先前运行不同时强制替换该对象之外什么也不做。

为了强制null_resource替换您的配置程序并因此强制其关联的配置程序重新运行,则需要使用triggers通常保持不变的值填充参数,但如果发生更改,则会导致配置程序重新运行。

在您的情况下,您的值似乎var.MyProj可以用作触发器,但因为它triggers是字符串映射,我们需要首先将其编码为字符串。在这种情况下,JSON 编码可能是一个合理的答案:

resource "null_resource" "nullr" {
  for_each = var.MyProj

  triggers = {
    settings = jsonencode(each.value)
  }

  provisioner "local-exec" {
    command = "bash /home/myscript.sh ${each.value.name} ${each.value.progrmme}
  }
}
Run Code Online (Sandbox Code Playgroud)

由于triggers资源的每个实例仅引用当前资源each.value,因此添加新条目var.MyProj不应影响资源的任何现有实例,因此不会重新运行任何配置程序。但是,如果您编辑现有密钥之一,它将使用新设置重新运行。

如果您期望需要重新运行特定资源的配置程序,即使其名称或“progrmme”都没有更改,那么您可能希望向元素类型添加第三个属性,该属性是您想要的var.MyProj整数或某些特殊字符串标识符每次需要重新运行时都会更改。然后,您可以更改该属性的值以强制它重新运行,即使它将重新运行与以前相同的程序。

另一种需要考虑的情况是如果内容发生myscript.sh变化会发生什么。如果您想在每次更改时重新运行脚本,那么您可以添加另一个triggers条目来捕获文件的校验和,因此每次文件更改时该校验和都会更改:

resource "null_resource" "nullr" {
  for_each = var.MyProj

  triggers = {
    settings        = jsonencode(each.value)
    script_checksum = filesha256("/home/myscript.sh")
  }

  provisioner "local-exec" {
    command = "bash /home/myscript.sh ${each.value.name} ${each.value.progrmme}
  }
}
Run Code Online (Sandbox Code Playgroud)