【问题标题】:Terraform destroy --target behaviourTerraform destroy --target 行为
【发布时间】:2018-10-01 10:49:16
【问题描述】:

我只是在使用 terraform 和 terraform destroy 参数。如果我 有三个节点,我用terraform destroy --target 删除了其中一个节点我有以下内容:

$ terraform state list
packet_device.jenkins-node[0]
packet_device.jenkins-node[1]
packet_device.jenkins-node[2]
$ terraform destroy --target packet_device.jenkins-node[1]
....
....
....
$ terraform state list
packet_device.jenkins-node[0]
packet_device.jenkins-node[2]

如果我将节点数减少到两个,terraform 会破坏 jenkins 节点 2 和 创建一个新的(jenkins 节点 1)。计数仍然是两个,但是 terraform 销毁一台服务器并创建一个新服务器。有什么办法可以禁用这个 行为?

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

packet_device.jenkins-node.2: Refreshing state... (ID: XXXX)
packet_device.jenkins-node.0: Refreshing state... (ID: XXXX)
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

  + packet_device.jenkins-node[1]
      access_private_ipv4:     "<computed>"
      access_public_ipv4:      "<computed>"
      access_public_ipv6:      "<computed>"
      always_pxe:              "false"
      billing_cycle:           "hourly"
      created:                 "<computed>"
      facility:                "sjc1"
      hardware_reservation_id: "<computed>"
      hostname:                "jenkins-eloy"
      locked:                  "<computed>"
      network.#:               "<computed>"
      operating_system:        "ubuntu_17_10"
      plan:                    "baremetal_0"
      project_id:              "ea13e749-0b1b-4c0d-9701-d0a3df7391f2"
      public_ipv4_subnet_size: "<computed>"
      root_password:           "<sensitive>"
      state:                   "<computed>"
      updated:                 "<computed>"

  - packet_device.jenkins-node[2]


Plan: 1 to add, 0 to change, 1 to destroy.

如果我使用三个节点设置 terraform 计划,我会得到以下结果:

$ export TF_VAR_nodes=3
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

packet_device.jenkins-node.0: Refreshing state... (ID: 02287fed-c281-4027-8603-bcad6db8b8e6)
packet_device.jenkins-node.2: Refreshing state... (ID: f35fa202-423d-4e02-9d18-1f1bd7f7a3ef)
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

  + packet_device.jenkins-node[1]
      access_private_ipv4:     "<computed>"
      access_public_ipv4:      "<computed>"
      access_public_ipv6:      "<computed>"
      always_pxe:              "false"
      billing_cycle:           "hourly"
      created:                 "<computed>"
      facility:                "sjc1"
      hardware_reservation_id: "<computed>"
      hostname:                "jenkins-eloy"
      locked:                  "<computed>"
      network.#:               "<computed>"
      operating_system:        "ubuntu_17_10"
      plan:                    "baremetal_0"
      project_id:              "ea13e749-0b1b-4c0d-9701-d0a3df7391f2"
      public_ipv4_subnet_size: "<computed>"
      root_password:           "<sensitive>"
      state:                   "<computed>"
      updated:                 "<computed>"


Plan: 1 to add, 0 to change, 0 to destroy.

有什么想法吗?

【问题讨论】:

  • 为什么这是您首选的方法,而不是减少资源数量和重新应用基础架构的标准方法?

标签: terraform


【解决方案1】:

没有。但是,如果您想销毁 packet_device.jenkins-node[1],您应该运行

terraform state mv packet_device.jenkins-node.2 packet_device.jenkins-node.1

所以节点 2 变成节点 1

【讨论】:

  • @Tiemen 有时操作员永远不会回到问题上,有时他们不知道网站是如何工作的,碰巧没有答案被标记为已接受。此外,在很多问题中,被接受的答案并不是最受好评或最好的,所以这并不是什么大问题。
  • 这不会破坏实例。它只会更新本地状态文件。在下一次应用时,将刷新状态并重新创建资源。导致重复。
  • @GeorgeJ 他在问如何删除第二个节点,然后缩小到仅保留第一个和第三个节点的 2 个节点。
  • 是的,但问题是他的资源是由索引标识的。从状态中删除它不会破坏正在运行的实例。如果他从状态中删除它,他需要在 terraform 之外手动删除它。
  • @GeorgeJ 我不确定你在说什么。第一个 sn-p 的代码 terraform destroy --target packet_device.jenkins-node[1] 会进行有针对性的销毁,然后我们在 state 中移动东西。
【解决方案2】:

更新基础架构的唯一安全方法是编辑文件、计划和应用。上面列出的所有其他方法仅适用于非正常情况。并且随着时间的推移,您的状态会从您正在运行和支付的实际基础设施中转移。


您的 terraform 基础架构似乎在某处包含 count

这样

module "packet_device" "jenkins_node" {
    count = 3
    ...other configs using ${count.index}
}

如果是这样,则使用计数时有一个限制,即您不能只增加和减少计数来放大和缩小。

由于您使用的是计数,因此 terraform 以索引格式存储每个模块的状态。 [0: {module1},1: {module2},2: {module3}] 并且当您将计数减少到 2 或删除单个实例时,会导致索引发生变化,而 terraform 会将其标记为更改。因为它将索引视为资源的标识。

假设您删除了索引 0,您最终会得到 [0: {module2},1: {module3}]

module2 将有一个新的索引为 0,而 module3 将有一个新的索引为 1。因此 terraform 将不得不销毁并重新创建这些模块,因为它不知道发生了什么。

很遗憾,您无法使用计数配置来阻止这种行为。


您需要做的是使用映射或for_each,这样资源将通过键匹配,而不是通过索引。因此移除或添加其他资源(在同一块中)不会相互影响。

这只是一个例子......

module "packet_device" "jenkins_node" {
    for_each = toset(["key1", "key2", "key3"])
    ...other configs and access the value by ${each.value}
}

documentation 提供有关 for_each 的更多信息。

【讨论】:

    猜你喜欢
    • 2021-12-08
    • 2017-09-06
    • 2020-05-19
    • 2016-09-24
    • 2021-12-02
    • 2020-06-03
    • 2019-06-25
    • 2019-12-13
    • 2021-11-16
    相关资源
    最近更新 更多