【问题标题】:Terraform state - change resource positionTerraform 状态 - 更改资源位置
【发布时间】:2021-11-01 17:24:07
【问题描述】:

很久以前在我们的一个账户中创建了 AWS 私有子网。这些私有子网中没有匹配的公共子网和资源。所以下面,aws_subnet.private_subnets[0]aws_subnet.private_subnets[1] 是空子网

aws_subnet.private_subnets[0]
aws_subnet.private_subnets[1]
aws_subnet.private_subnets[2]
aws_subnet.private_subnets[3]
aws_subnet.private_subnets[4]

子网是使用 terrform 创建的,如下所示:

 resource "aws_subnet" "private_subnets" {
      count      = length(split(",", var.private_subnets))
      cidr_block = element(split(",", var.private_subnets), count.index)

其中var.private_subnets 是一个包含我们的 5 个不同 CIDR 块的字符串。

我想整理一下,但我尝试从字符串中删除前两个 CIDR 块,但它仍然尝试重新创建它们,因为它想要更改:

aws_subnet.private_subnets[2]aws_subnet.private_subnets[0]

aws_subnet.private_subnets[3]aws_subnet.private_subnets[1]

aws_subnet.private_subnets[4]aws_subnet.private_subnets[2]

我不希望这种情况发生,因为我需要在新子网中重新部署所有 EC2。那么解决这个问题的最佳方法是什么?是否将它们从状态中删除,使用:

terraform state rm aws_subnet.private_subnets[0]

然后将它们更改为:

terraform state mv 'aws_subnet.private_subnets[2]' 'aws_subnet.private_subnets[0]'

我没有在 state 上做很多工作,打破它可能会导致很多问题,所以只是想确定一下。或者更好的选择是在 AWS 中手动删除它们,然后再次运行 terraform? - 我不确定这是否会导致我目前遇到的同样问题

【问题讨论】:

    标签: amazon-web-services terraform subnet


    【解决方案1】:

    如果您以影响哪些对象属于哪些索引的方式更改源集合,那么确实需要使用terraform state mv 之类的策略来向 Terraform 解释索引分配是如何变化的。

    在您的情况下,情况似乎如下:

    terraform state rm 'aws_subnet.private_subnets[0]'
    terraform state rm 'aws_subnet.private_subnets[1]'
    terraform state mv 'aws_subnet.private_subnets[2]' 'aws_subnet.private_subnets[0]'
    terraform state mv 'aws_subnet.private_subnets[3]' 'aws_subnet.private_subnets[1]'
    terraform state mv 'aws_subnet.private_subnets[4]' 'aws_subnet.private_subnets[2]'
    

    这些操作的顺序很重要,因为 Terraform 无法跟踪同一地址上的两个不同对象,因此我们需要始终释放目标索引,然后再将另一个实例移入其中。


    您的var.private_subnets 似乎是一个包含逗号分隔的 CIDR 块列表的字符串。在现代 Terraform 中,通常最好将其声明为一组字符串 - 这样每个 CIDR 块都是一个单独的元素 - 然后使用 for_each 而不是 count 以便 Terraform 将通过 CIDR 跟踪实例块字符串本身,而不是它们在列表中的任意位置。

    variable "private_subnets" {
      type = set(string)
    }
    
    resource "aws_subnet" "private_subnets" {
      for_each = var.private_subnets
    
      cidr_block = each.value
    }
    

    此更改需要使用 terraform state mv 进行一些迁移工作,因此,既然您无论如何都会做这项工作,那么同时进行此更改可能是有益的,从而避免进行迁移两次进入现代成语。

    您没有在问题中包含 CIDR 地址的实际值,因此我将假设像 10.x.0.0/16 这样的连续地址,其中“x”与索引相同。在该方案下,您的迁移将如下所示:

    terraform state rm 'aws_subnet.private_subnets[0]'
    terraform state rm 'aws_subnet.private_subnets[1]'
    terraform state mv 'aws_subnet.private_subnets[2]' 'aws_subnet.private_subnets["10.2.0.0/16"]'
    terraform state mv 'aws_subnet.private_subnets[3]' 'aws_subnet.private_subnets["10.3.0.0/16"]'
    terraform state mv 'aws_subnet.private_subnets[4]' 'aws_subnet.private_subnets["10.4.0.0/16"]'
    

    请注意,在这种情况下,新地址的实例键是包含实际 CIDR 前缀的字符串,而不是列表中的整数位置。

    这意味着它们不再有任何固有的顺序,Terraform 会理解,如果你向集合中添加新的东西意味着创建一个新的子网,如果你从集合中移除一个项目意味着移除相应的子网.如果您将来删除 CIDR 前缀,在执行此一次性迁移后,您将不需要 terraform state mv 来修复这些位置,因为它们不再具有特定位置。

    【讨论】:

      猜你喜欢
      • 2022-10-19
      • 1970-01-01
      • 2014-04-20
      • 2019-05-29
      • 1970-01-01
      • 2021-03-03
      • 1970-01-01
      • 2021-12-11
      • 2020-08-01
      相关资源
      最近更新 更多