LabHub
学习 学习路径 课程

Terraform/OpenTofu 基础

依赖图与状态文件的内里

在 LabHub 中继续学习

一句话总结

Terraform不是按照文件中写下的顺序移动,而是按照引用创建的图表的顺序移动。该图表是状态文件的dependencies像化石一样留下来,即使代码中资源消失后,也会告诉删除顺序。

概念图: 引用创建的图表 · 关系 · 在 · 第一,dependson多米诺骨牌。

为什么需要这个?

在Shell脚本中,顺序由人决定。如果资源有五个,从上到下读就可以了,但如果达到三十个,每次插入新的资源时,都要由人重新判断“这个应该放在哪里后面”。而且即使是彼此无关的资源也会排成一行,所以制作所需的时间就会直接相加。

声明型工具颠覆了这个问题。人只写关系,顺序却很多。A制作的时候B使用的值就是“B先”的宣言。工具将这种关系汇总起来,制作方向图,并进行相位排序,同时处理彼此无关的东西。删除时,将相同的图反向运行。

怎么行动

产生依赖性的方法有两种。

方式 怎么产生 什么时候使用
默认依赖性 通过公式引用其他资源的属性时,自动 基本。当实际需要值时
明确依赖性 depends_on = [주소]直接写下来 没有参考,但应该有顺序的时候

大部分是默示的足够了。depends_on这种情况需要的是值中没有显示的附加效果**。例如,在附加IAM策略之前,资源生成失败,但该策略的值没有在代码中使用的情况。

depends_on像习惯一样粘在一起的话,图表就会变粗。那样的话,两种都是损失。第一,可以同时处理的事情排队执行时间变长。第二,前面资源再生时,后面资源也一起再生范围变宽。

状态文件也一起看吧。terraform state list是只吐出一个注册地址的一行最快的确认手段。需要用机器处理的时候terraform show -json使用。这个输出的资源列表是values.root_module.resources在下面,在每个项目中address有附着物jq处理起来很好。直接读取状态文件本身的话seriallineageversionresources可以看到。

.terraform.lock.hcl此时读起来也值得。里面有provider "registry.opentofu.org/hashicorp/local"与同一区块确定的version,还有h1:或者zh:包含以开头的哈希。版本的意思是“决定用什么”,哈希的意思是“实际收到的东西是否是正确的”。

在现场相遇的样子

**第一,depends_on多米诺骨牌。**一旦出现顺序问题,人们就会四处走动。depends_on开始附加。几个月后,只是修改了一个数据库参数,计划中却出现了“再生性12件”。把图表加粗的代价总是以后要收取的。

**第二,删除顺序不是代码,而是状态。**如果从代码中删除资源,该资源的关系就会从代码中消失。尽管如此,工具还是可以按正确的逆序删除,这是因为状态的dependencies因为还保留着关系。用手编辑状态是危险的原因之一。

**第三,漂移不是特别的功能。**如果在代码之外修复正在管理的资源,下一步plan在这个查询阶段发现差异并试图恢复。在应对障碍时,在控制台急忙修改的设置在下次发布中悄无声息地消失,这就是发生在这里的事故。紧急更改必须以代码形式恢复。

虽然有依赖性,但是不知道Terraform的时候

Terraform在参考中读取顺序。aws_instance.web.subnet_id像这样不同的 使用资源的属性时,自己知道那个资源必须先被创造出来。问题是 是没有参考存在的依赖性

resource "aws_iam_role_policy" "app" { ... }

resource "aws_instance" "app" {
  # 정책이 붙기 전에 인스턴스가 떠서 부팅 스크립트가 실패한다
  depends_on = [aws_iam_role_policy.app]
}

depends_on银只在这样的时候使用。习惯性地粘上的话,甚至可以并行使用。 排成一排的应用变慢,图形无法在人眼中看到。可以作为参考表示。 如果有的话,总是最好参考一下。

计划中的顺序不是执行顺序。terraform plan的输出是字母 接近顺序。实际顺序由图表决定。

terraform graph | dot -Tsvg > graph.svg

资源的更换会引发连锁反应。在计划中# forces replacement附加的属性 有的话,那个资源会被删除,然后重新创建。引用那个资源的东西也一起 因为变了,所以修改了一行,但计划里出现了十二个的情况。这时 create_before_destroy打开的话,会先创建新东西,然后删除旧东西,但是名字 在全军中唯一需要的资源反而发生冲突。在名字上random_id的 粘贴或name_prefix使用它的理由就是这个。

lifecycle {
  create_before_destroy = true
  ignore_changes        = [tags["LastModified"]]
}

ignore_changes把对象写得更具体。如果完全忽略的话,那个资源实际上是 离开管理。就像在外面贴的标签一样,只有知道谁为什么要换的属性 写。

count相反for_each使用。count制作的列表中,地址是编号。 删除中间的一项的话,后面的东西会依次被拉走,全部是完好的资源。 被更换。for_each的地址是钥匙,所以只要删除就会消失。

下次实习要做的事情

/root/tf/state在积累资源的同时,确认仅通过引用而产生依赖性的状态,在没有引用的地方depends_on附上看看。提取状态地址列表和JSON表达式,serial·lineage·制作包含资源数量的元数据文件。然后用手删除正在管理的文件,看到漂移被计划下来后,从锁定文件中读取提供商版本。最后,制作3阶段依赖链并记录顺序。