Terraform - 删除除一个之外的所有资源

51

我有一个Terraform 0.11项目,包含30-40个不同的资源。我想删除其中除了几个逻辑相关的资源之外的所有资源。

我正在寻找类似于terraform destroy --except=resource-id的功能,但当然这样的命令并不存在。

是否有办法在不过多编写脚本的情况下实现这一点(Terraform管理员使用各种操作系统)?也许使用模块可以使该过程更加容易?


2
答案是不要以这种方式构建您的代码库。同一目录中的内容应该都可以同时创建或销毁。部分应用更改是一个紧急出口,而不是依赖的东西。 - ydaetskcoR
@ydaetskcoR 这很有道理。如果您可以将其编写出来,我会接受这个答案。 - rath
1
感觉可能是重复的,请让我查一下,否则我会在这里写下答案。 - ydaetskcoR
1
那么弹性公网IP呢?例如,您已将这些列入白名单,并且不想破坏它们,因为您需要在其他地方进行更改控制,您可以设置Terraform以创建并标记为prevent_destroy。在这里,prevent_destroy的作用只是使您的terraform destroy命令失败。您可以在terraform之外创建eip并仅管理关联,但两者都感觉可以更好地处理。 - krystan honour
这些答案都不令人满意。我有一组相关的基础设施,并且我希望在销毁后保留几个项目,并且它们应该保留在TF的状态中。用例:一些S3存储桶(最近由于名称冒用而“丢失”了一个短暂的测试环境的S3存储桶名称);以及需要使用非AWS DNS提供程序进行手动验证的ACM证书。对于来去匆匆的环境(即为了降低成本而在夜间关闭的测试环境),我认为这并不过分。 - Chuck Batson
7个回答

98

terraform destroy 命令目前没有 --except 功能。如果你真的想要实现这个功能,并且知道你在做什么,这里是一个解决方法。

# list all resources
terraform state list

# remove that resource you don't want to destroy
# you can add more to be excluded if required
terraform state rm <resource_to_be_deleted> 

# destroy the whole stack except above excluded resource(s)
terraform destroy 

那么这些命令为什么适用于你的想法呢?

状态(*.tfstate)用于将实际世界的资源映射到您的配置中,跟踪元数据。

terraform state rm 仅从状态文件(*.tfstate)中清除记录(资源),不会销毁实际资源。

由于您没有运行 terraform applyterraform refresh,在执行 terraform state rm 后,terraform 不会知道排除的资源被创建了。

当您运行 terraform destroy 时,它不会详细了解该排除资源的状态并且不会销毁它。 它将销毁其余部分。

顺便说一下,如果需要,您以后仍有机会使用 terraform import 命令将该资源重新导入。


7
现在这个资源的状态被孤立了,如果不删除它,Terraform 就不再对其进行管理,这并不是原帖作者想要的结果。虽然你可以在删除其他所有内容后再次导入它,但部分应用和销毁通常是一个不好的想法。 - ydaetskcoR
5
这对我的情况来说是一个不错的解决方法。正如ydaetskcor所说,它并不理想,但已经足够好了。 - rath
它正常工作。 - Vinoth Ramamoorthy
import 是什么意思?terraform import <resource_to_be_reimported>是什么? - Panda
导入命令对于每个资源都是不同的,您需要参考 Terraform 文档。 - BMW

13

目前,针对除你想要的数据资源之外的每个资源进行定位可能是唯一的方式:

#! /bin/bash

while read -r resource; do
    terraform destroy -target="$resource"
done < <(terraform state list | grep -vE "^data\." | grep -vE "dont_remove|also_important")

如果你正在使用一个模块,"^data." 模式需要改为 ".data."。 - lost
而且(显然,但我错过了!)它不使用TF的依赖图,因此除了简单情况外,这可能不起作用。 - lost

7
要删除除某些资源外的所有堆栈,您需要执行以下操作:
  1. 备份当前状态:terraform state pull > bkup.json
  2. 列出所有资源:terraform state list
  3. “rm”您想要保留的资源:terraform state rm "aws_myresource"。它不会从云中删除资源,而只是从terraform视角中删除。
  4. 销毁您的堆栈:它将从云中删除除刚才“rm”的资源之外的所有资源。terraform destroy
  5. 现在您拥有一个空状态(0个资源)。保存它以便能够编辑它:terraform state pull > state-to-edit.json
  6. 通过将bkup.json中的资源对象{}添加到.resources []块中来编辑state-to-edit.json。您还需要将.serial值增加1
  7. 推送修改后的状态:terraform state push ./state-to-edit.json
  8. 您可以使用terraform planterraform state list验证您仍具有所需的资源并删除了所有其他资源。

1
这是唯一一个做到了 OP 所要求的答案。我只是很遗憾这是必要的。另请参阅这个将近四年历史的问题。 - Chuck Batson
1
谢谢@ChuckBatson,我已经将它添加到问题中以增加可见性。希望能帮助到大家。 - Rémi F.
我不知道为什么terraform在某人的灵魂中带有那么多的恨意。 - Lethargos

1

BMW的回答是最好的选择,如果你只需要摧毁资源,而不改变代码。也就是说,如果你打算在以后的某个时间重新启动这些资源。

如果你只想删除资源,正确的解决方案是删除你想要销毁的Terraform定义,然后进行正常的terraform apply操作。就像你添加资源一样。

(我知道这是一个旧问题,但我很惊讶没有人提到替代方案。OP的用例似乎已经被其他答案涵盖了,所以这个答案是为了其他人在这里遇到问题时提供帮助。)


1
我有一个不同的解决方案。那些我不想在 "terraform destroy" 中删除的资源,我会使用 CLI 创建为 "null_resource"。您仍然可以在 terraform 中使用您的变量。
例如(创建一个资源组,但由于 null_resource 而持久存在):
resource "null_resource" "backend-config" {
        provisioner "local-exec" {
        command     = <<EOT
    az group create --location ${var.Location} --name ${var.Resource_group_name} --tags 'LineOfBusiness=${var.Lob}' 'Region=${var.Region}' 'Purpose="Terraform-Primary-Resource-Group-${var.Lob}'
    EOT
        interpreter = ["Powershell", "-Command"]
      }
    }

现在,如果您使用terraform destroy销毁资源, 任何null_resource都将保持完好无损。

0
  1. 列出资源:

    terraform state list
    
      data.terraform_remote_state.rg
      azurerm_postgresql_database.postgresql_database
      azurerm_postgresql_server.postgresql_server
    
  2. 移除资源:

    terraform destroy -target azurerm_postgresql_database.postgresql_database -auto-approve
    

-2

terraform destroy -target 资源类型.名称 -target 资源类型2.名称


你能否评论我的答案有什么问题? - kensai
6
问题是如何只保留一个资源并摧毁其他资源,您展示了(没有解释)如何摧毁单个资源。如果有人盲目地按照您的答案操作,他/她会摧毁他/她想要保留的那个资源。 - Marco Necci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接