忽略不想要的 Terraform Provider 属性变更
忽略不想要的 Terraform provider attribute changes
2025年3月23日 · 阅读约需 3 分钟 · (562 字)
问题所在!
我偶尔会遇到一些 Terraform provider,它们会以一种不太理想的方式来处理某个属性。
这意味着,后续的运行会发现该属性发生了变更(与传递的属性相比),并希望修改它。
举个例子!…
Docker Terraform provider
(由 kreuzwerker
提供:D https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs) 会将 “image” 属性修改为镜像的 SHA 摘要…
这意味着,如果我创建:
resource "docker_container" "my_important_container" {
...
image = "base-image-for-my-important-container:v2.20.2"
...
}
在 terraform refresh
之后,image
属性将被读取为 SHA 摘要。 这意味着下次运行 Terraform 时,它将希望重新创建容器,将镜像从 SHA 摘要更改为原始命名镜像。
对于某些资源来说,这可能没问题,也许是一个原地更新,什么都不会改变……但在这种情况下,它会强制重新创建,对于容器来说,这意味着中断。(是的,是的,这是一种非常糟糕的部署容器的方式……但这仅用于 Homelab,嘘!……看看我当时在处理什么 (https://github.com/MatthewJohn/vault-nomad-consul-terraform),然后再抱怨!)。
无知是福
当然,大多数人实现这一目标的方式是简单地忽略对此属性的更改:
resource "docker_container" "my_important_container" {
...
image = "base-image-for-my-important-container:v2.20.2"
...
lifecycle {
ignore_changes = [image]
}
}
当然,这会起作用……至少可以阻止资源的重新创建并让 Terraform 闭嘴……
但假设我做了如下更改:
diff
- image = "base-image-for-my-important-container:v2.20.2"
+ image = "base-image-for-my-important-container:v2.20.3"
好吧,当然,一切都乱套了……我已经进行了更改以部署到新版本,并且我运行了 Terraform,它显示一切良好!……但事实并非如此,我们告诉它忽略它,它也确实这样做了。只是,我们在 3 年后忘记了这一点,我们的流水线显示绿色,表明 Terraform 已经计划/应用,所以一切都很好。
倾听被忽略的
我喜欢使用的一个小技巧是简单地创建一个 null_resource
,由我们真正关心的属性值触发,并根据此触发器配置替换。
例如:
locals {
image = "base-image-for-my-important-container:v2.20.2"
}# Handle changes to image, which are ignored by the container resource
resource "null_resource" "container_image" {
triggers = {
image = local.image
}
}
resource "docker_container" "my_important_container" {
...
image = local.image
...
lifecycle {
ignore_changes = [image] # When container image name changes
replace_triggered_by = [
null_resource.container_image,
]
}
}
瞧……只要镜像名称没有更改,触发器就不会被重建。 docker_container
愉快地使用一些垃圾/不可能真正验证的/我永远不会传入的 SHA 摘要,Terraform 正在忽略它。 一旦镜像发生变化,虽然 docker_container
资源忽略了属性更改,但 null_resource
肯定不会,并且该重新创建随后会触发容器重新创建。
改进?
老实说,也许 docker_container
的 image
属性可以设置为 null_resource.container_image.triggers.image
,但我总是将镜像作为变量传入,这减少了我的重复。
话虽如此,我喜欢使用所有权所在的属性……我不认为 null_resource
是镜像的“提供者”,而更多的是一个额外的使用者。 所以也许一个 local 变量就足够了。
而且,老实说,我应该创建一个 PR 给 provider,以处理将镜像名称解析为 SHA 摘要,然后在强制重新创建之前进行比较……但是,嘿,有时我们没有时间修复所有小事情!