Day 18-更改 state 有其风险,State manipulation 有赚有赔(?),更改前应详阅官方文件说明书

更改 state 有其风险,State manipulation 有赚有赔(?),更改前应详阅官方文件说明书

课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days

赛後文章会整理放到个人的部落格上 http://chechia.net/

追踪粉专可以收到文章的主动推播

https://ithelp.ithome.com.tw/upload/images/20210901/20120327NvpHVr2QC0.jpg


Review

本篇讲解进阶的 terraform state 操作,请复习基本State 操作基本 Backend 的相关概念

  • state 内含 terraform 运作产生的最终资料与中间产物(ex. 变数,random resource...等)
  • state 内含连结 .tf resource 与公有云上远端 resource 的,terraform 仰赖 resource metadata (ex. 远端 resource 的 id),来对应 .tf resource
  • state 实作逻辑,由各家 provider 实作,state 内也会包含 provider 与 public cloud api 沟通时需要的资料

Standard state workflow

一般来说,我们可以完全仰赖 provider 自动管理 state,不需要手动干涉 state 内容。此时 state 的 workflow 很单纯:针对每个 root module

  • terraform init 初始化 state
  • terraform plan
    • lock state
    • refresh state 更新 state 与远端 resource 的状态
    • provider 依据最新 state 与 .tf 的差异,计算应该变更计画
  • terraform apply
    • lock state
    • 进行 apply,由 provider 发出 api 到 public cloud
    • 等待 public cloud response,并依据 response 更新 state

前面 18 天的课程,我们都是依照上面的流程,让 terraform 自动管理 state

state manipulation: the bad

更改 state 有其风险,State manipulation 有赚有赔(?),更改前应详阅官方文件说明书

Terraform 官方文件对於 state manipulation 的描述 标记 important note

Important: Modifying state data outside a normal plan or apply can cause Terraform to lose track of managed resources, which might waste money, annoy your colleagues, or even compromise the security of your operations. Make sure to keep backups of your state data when modifying state out-of-band.

重要!在正常 plan / apply 以外的流程更改 state,可能造成 terraform 无法追踪远端 resource

  • 可能会浪费云端 resource 的花费
  • 高机率会惹恼同事
  • 或是造成安全性的漏洞
    如果要操作 state manipulation,务必先备份

State addressing

在进到更改 state 之前,要来细看 terraform 是如何 address state

azure/foundation/compute_network 为例说明。首先回忆一下 .tf 内容

  • 使用 local module modules/compute_network
  • module 内部又使用 https://github.com/Azure/terraform-azurerm-network 的 remote module
  • 忘记的话记得去 https://github.com/Azure/terraform-azurerm-network 回忆一下
  • remote state 在 azure blob storage 上,可以上 azure console -> storage browser 看到 .tfstate

由於我们已经 apply 过,这边使用 state list 列出现有的 state

  • state 的表示是用 state address 代表
    • resource 与 module block 的名称可能重复,但是一个 path 底下的 block name 都是唯一的
    • 也就是说每个 resource address 都代表一个 resource / data source
cd azure/foundation/compute_network
terragrunt state list

module.network.data.azurerm_resource_group.network
module.network.azurerm_subnet.subnet[0]
module.network.azurerm_subnet.subnet[1]
module.network.azurerm_subnet.subnet[2]
module.network.azurerm_virtual_network.vnet

我们这个 root module (azure/foundation/compute_network) 产生五个 resource

  • 一个 data source,意思是这个 data block 从远端获取一个 data source,例如远端的物件,以及物件的参数,把 data 存到 state 中,让其他 resource 引用。但本身不会 create 远端的 resource
  • 一个 multi-instance resource module.network.azurerm_subnet.subnet(s)
    • 这个 resource 是 multi-instance,在呼叫 / address 其中一个 instance 时候,可以使用 module / resource index (ex. [0])
    • 如果 module / resource 是 collection,addressing 会加上 index
  • 一个 single instance resource module.network.azurerm_virtual_network.vnet

module / resource 的命名也很直观

  • module + name
  • resource type + name
  • 然後可以一直串下去,越多层越长,复杂的 module 底下 address 接连到天边...(远目)
module.<module-name>.azurerm_virtual_network.<resouce-name>

Why state manipulation

上面把 state manipulation 说得这麽可怕,那 terraform 都自动把 state 维护好,我们有什麽动机需要手动来更改 state?

实务上比较常见到的例子

  • inspect state,我只是想看一下 state 内容
  • 使用 terraform taint 来强制 resource recreate
    • 如果 module 有使用 lifecycle meta-argument 中的 ignore changes,就有机会搭配使用
    • 或是 provider 的新功能,但支援不是那麽完整的时候,我们强迫 recreate
  • resource / module 重新命名,rename resource 在 terraform 会被视为 delete + create
  • import 原本不是 terraform 产生的 resource,导入 terraform 管理,import 到 terraform 中
  • Disaster Recovery,因为出事了阿北,state 坏了只好来手动修

Let's talk about resource / module rename

rename resource / module 应该是常见的需求,特别是针对开发中的 module,会希望让 resource 的名称更直观

  • naming 也会随 module 的编辑而逐渐改变
  • 例如本来 module 中只有一个 vm 所以命名为 vm.main,之後觉得要做 High Availability,所以 rename 变成 vm.master + vm.slave[0] + vm.slave[1]

从 resource addressing

  • module + name
  • resource type + name

如果我们把 module.network.azurerm_virtual_network.vnetazurerm_virtual_network.vnet rename 成为 azurerm_virtual_network.main

  • address 改变了,terraform 有办法辨识两个 resource address 是相同 resource 吗?
  • 答案是不行,terraform 会看到
    • module.network.azurerm_virtual_network.vnet 不见了
    • 多一个 module.network.azurerm_virtual_network.main
    • 因此觉得使用者是想要
      • 删掉有 state 存在,但是 .tf 中不见的 module.network.azurerm_virtual_network.vnet
      • 没有 state 存在,但是 .tf 中出现的 module.network.azurerm_virtual_network.main 应该要产生
- module.network.azurerm_virtual_network.vnet {
  }

+ module.network.azurerm_virtual_network.main {
  }

1 to create, 1 to delete

这也是 terraform,应该说是 RESTful API 常见的问题

  • 如何从 api 端,判断使用者的意图,是希望 resource 的 rename,而不是 delete + create

在这种情形下,如果我们希望的是 rename,便可以更改 state

  • 把 state 中的 module.network.azurerm_virtual_network.vnet -> module.network.azurerm_virtual_network.main
  • 於是 terraform 就会看到 .tf 中有 module.network.azurerm_virtual_network.main,state 中也有 module.network.azurerm_virtual_network.main,两个是对在一起的
  • 而且 remote resource 的 id 仍然能对照公有云上正确的 resurce

state mv 方法很多种,例如:

  • 直接打开 editor,对准 terraform.tfstate 档案,vim 下去直接把路径改掉 (DANGER)
  • 或是使用 terraform 指令, terraform state mv 来

Don't do this! Edit Local State with Editor

State manipulation 有其风险有赚有赔(?)工程师应详阅官方文件公开说明书。

今天我们遇上上面描述的情形,被迫要手动调整 state,然而 state 更改方式许多种,使用 editor 直接 edit 大概是最容易出错的一种

  • 复杂的 nested json,看了眼睛痛,没人想用手维护 json
  • 组织越复杂的 json 越容易犯错
  • non-programmatic approach,富含 human error,难以复现 reproduce,难以自动化与标准化

当使用 local state 进行变更时(ex. apply),本地会有一个版本的 terraform.tfstate.backup 档案,是 terraform 使用 local state 的时候,一个贴心的小功能。如果

如果 terraform.tfstate 跟 terraform.tfstate.backup 都改坏了,那复原的步骤就会变得非常麻烦,而且一个不小心就会弄坏远端的 resource。这在 prod 发生的话不是开玩笑的

附带一提,这时就体现出 state versioning 的优势,如果使用的 backend 有支援 state versioning,远端的 backend 上会保留非常多以前 apply 的 state,万一真的不幸搞坏最近几个版本,还是可以 checkout 更早版本的 state,协助回朔

然而,版本离越远,回朔的过程越痛苦。这是一个惹恼同事的好方法 ;)

Homework

烂方法没试过不知道他有多烂

  • 使用 local state apply,或是使用之前 _poc 内使用 local backend 的范例
  • rename 过去写过的任何 remote
  • 备份 terraform.tfstate
  • 只用最爱的 editor 直接编辑 terraform.tfstate,更改 state resource address 到新的 resource.name
  • 再次 terraform plan,看 terraform 是正常运作

<<:  Day 06 Heroku、Heroku CLI、Git push建置

>>:  [Day 3]从零开始学习 JS 的连续-30 Days---字串

Day 27. 混血的最萌 - 混合加密系统(hybrid cryptosystem)

大家好,我是羊小咩 这章来谈谈混合加密系统(hybrid cryptosystem) 现今大多传送...

Eloquent ORM - 写入资料

建立资料 写资料前要先有栏位,找到前面指令建立的 create_todos_table migrat...

React Native 优缺点,如果现在开始做会选哪个

我们因为只有一个工程师,做 App 的话跨平台开发是很自然的选项。 在2018年开发时,当初只有 R...

html清单

今天学习如何在网页上显示清单列表,我们需要用到ul li与ol li 首先是ul li,在body里...

Day5给你一个漂漂的导览列大家说好不好!

延续昨天,今天来完成一个导览列吧!! 首先先在components创一个navbar.vue 像昨天...