TT Lab
开始
学习 学习路径 课程

Terraform/OpenTofu 基础

第一份声明,以及怎么读状态文件

在 TT Lab 中继续学习

目标

亲手确认一条声明会同时产生真实文件和状态文件这两个结果,并学会打开状态,读懂其中的资源地址、serial 和依赖关系。

为什么重要

初次接触声明式工具时,看上去像是在“背命令”,但真正要学的是工具依据什么来做判断。Terraform 会比较代码(期望状态)、状态文件(最后所知的状态)和真实基础设施(当前存在的东西)这三者来生成计划。所以一旦丢失状态文件,工具就会把已经存在的资源当作“第一次见到”而试图重新创建,而状态中残留的幽灵资源则会被它说成“要删除”。本实验要用 jq 亲自打开状态,原因就在这里。还有一点:值是硬编码还是引用,不是个人喜好,而是图的问题。只有引用,工具才能知道顺序,以后前面的资源变化时,后面的资源也会一起更新。

步骤

  1. 把 /opt/lab/fixtures/terraform/starter/main.tf 复制到 /root/tf/first/main.tf,并在该目录中初始化。required_providers 块必须原样保留,初始化之后要生成 /root/tf/first/.terraform.lock.hcl 和 /root/tf/first/.terraform/providers,并且锁文件中必须记录 local provider。
  2. 在 main.tf 中声明一个类型为 local_file、名称为 hello 的资源。filename 为 /root/tf/first/out/hello.txt,存放内容的参数名是 content。
  3. 应用以创建 /root/tf/first/out/hello.txt。内容设为 hello opentofu。应用之后,local_file.hello 要登记在 /root/tf/first/terraform.tfstate 中,状态中记录的 content 与真实文件内容必须完全相同,并且状态的 version 必须是 4。
  4. 添加并应用一个类型为 random_pet、名称为 suffix 的资源。length 设为 2,不要指定 prefix。状态中要生成 random_pet.suffix,生成的名称必须是 단어-단어(韩文,意为“单词-单词”)的形式。
  5. 把 hello 的内容改为 hello labhub 并重新应用。文件内容和状态中记录的 content 都必须恰好是 hello labhub,并且状态的 serial 必须不小于 2。
  6. 用 /root/tf/first/out/temp.txt 创建一个类型为 local_file、名称为 temp 的资源,然后再把它移除。把移除时的输出保存到 /root/tf/first/out/destroy.txt。结束后,temp.txt 文件和状态中的 local_file.temp 必须消失,而 local_file.hello 必须保留。
  7. 把状态中登记的资源地址列表保存到 /root/tf/first/out/state-list.txt。local_file.hello 和 random_pet.suffix 必须各占一行,且不得有 local_file.temp(在完成第 6 步之后再导出)。
  8. 用 /root/tf/first/out/summary.txt 创建一个类型为 local_file、名称为 summary 的资源。内容中必须同时包含 random_pet.suffix 生成的名称和 hello labhub,并且这两个值都必须通过引用其他资源的属性来填入。应用之后,状态中 local_file.summary 的 dependencies 里必须能看到 random_pet.suffix。

参考

初始化工作目录并获取 provider

把 /opt/lab/fixtures/terraform/starter/main.tf 复制到 /root/tf/first/main.tf,并在该目录中初始化。required_providers 块必须原样保留,初始化之后要生成 /root/tf/first/.terraform.lock.hcl 和 /root/tf/first/.terraform/providers,并且锁文件中必须记录 local provider。

fixture 中的初始文件里已经有 required_providers。把这个文件复制到工作目录再初始化,就会生成锁文件和 .terraform/providers。这个环境不走互联网,而是从镜像内的文件系统镜像源下载。

声明 local_file 资源

在 main.tf 中声明一个类型为 local_file、名称为 hello 的资源。filename 为 /root/tf/first/out/hello.txt,存放内容的参数名是 content。

在 resource "타입" "이름"(占位符依次为类型、名称)中,第二个标签就是地址的后半部分。注意存放文件内容的参数名不是复数形式。

应用,同时创建文件和状态

应用以创建 /root/tf/first/out/hello.txt。内容设为 hello opentofu。应用之后,local_file.hello 要登记在 /root/tf/first/terraform.tfstate 中,状态中记录的 content 与真实文件内容必须完全相同,并且状态的 version 必须是 4。

应用结束后,真实文件和 terraform.tfstate 会同时生成。比较状态中记录的 content 与真实文件内容是否相同——这两者出现偏差的状态就是漂移。也确认 version 字段是多少。

用 random_pet 生成随机名称

添加并应用一个类型为 random_pet、名称为 suffix 的资源。length 设为 2,不要指定 prefix。状态中要生成 random_pet.suffix,生成的名称必须是 단어-단어(韩文,意为“单词-单词”)的形式。

random_pet 会生成用连字符连接单词的名称。找出决定单词数量的参数是什么,并且不要指定前缀。

修改声明并重新应用

把 hello 的内容改为 hello labhub 并重新应用。文件内容和状态中记录的 content 都必须恰好是 hello labhub,并且状态的 serial 必须不小于 2。

只修改内容并重新应用,状态中的 serial 就会增加。状态中记录的值必须与真实文件完全相同,所以不要让末尾混入换行。

只挑出临时资源来删除

用 /root/tf/first/out/temp.txt 创建一个类型为 local_file、名称为 temp 的资源,然后再把它移除。把移除时的输出保存到 /root/tf/first/out/destroy.txt。结束后,temp.txt 文件和状态中的 local_file.temp 必须消失,而 local_file.hello 必须保留。

从声明中删除资源块并重新应用,就只有那个资源会消失。删除之前,先阅读输出,确认本应保留的资源没有被列为对象。

提取状态中登记的地址

把状态中登记的资源地址列表保存到 /root/tf/first/out/state-list.txt。local_file.hello 和 random_pet.suffix 必须各占一行,且不得有 local_file.temp(在完成第 6 步之后再导出)。

有一个子命令可以只显示状态中登记了什么,并且只显示地址。如果已经删除的资源仍留在列表中,说明步骤的顺序做错了。

用引用创建汇总文件

用 /root/tf/first/out/summary.txt 创建一个类型为 local_file、名称为 summary 的资源。内容中必须同时包含 random_pet.suffix 生成的名称和 hello labhub,并且这两个值都必须通过引用其他资源的属性来填入。应用之后,状态中 local_file.summary 的 dependencies 里必须能看到 random_pet.suffix。

用表达式引用其他资源的属性,依赖关系就会自动产生。如果把用眼睛看到的值直接写进字符串,文件内容虽然正确,但 dependencies 是空的,因此会失败。