Day 23-state manipulation 之五:terraform import,专案中途导入 terraform 必经之路

上篇介绍 state rm,强制 terraform 遗忘已经存在的 state。然而 state rm 後并没有说明如何修复或 undo,让 module 留在一个会激怒 team member 的状态XD

这篇介绍 state rm 的反向操作:terraform import

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

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

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

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


Terraform import

import 是在 terraform root command,用来 import 已经存在的 remote resource 到 state。可以看 官方文件 import 中描述

  • import 已经存在的 infrastructure (remote resource) 将他纳入 terraform 的管理中
  • 最常见的用例是,在一个还没导入 terraform 的专案中,已经有 infra 存在时,逐渐导入 terraform 时,陆续 import 到 terraform

要 import 之前,要先手写产生 .tf resource

  • ex. 如果要 import subnet[0],要先写 subnet[0] 的 resource 在 .tf 中
  • 然後使用新的 subnet[0] 的 resource address,将 remote resource import 近来

文件提到 Terraform 目前的 import 实作,只影响 state,不会产生 .tf resource。这是什麽意思?

  • 要 import 已经存在的 infra,却还要先写 .tf resource 再 import,这样不是很麻烦

另一个专案 Google Cloud Platform 推出的 terraformer 有提供直接 import 并产生 .tf 档案的方法

  • 留在 state 讲解完後再跟大家分享,这边先不提

import example

这边接续上堂课 state rm 的范例,直接使用 import

  • 注意这不是实务上常出现的例子,理想中你不会有一个队友,没事 state rm 东西

上堂课我们卡在这边

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.network.azurerm_subnet.subnet[0]: Creating...
╷
│ Error: A resource with the ID "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_subnet" for more information.
│
│   with module.network.azurerm_subnet.subnet[0],
│   on .terraform/modules/network/main.tf line 15, in resource "azurerm_subnet" "subnet":
│   15: resource "azurerm_subnet" "subnet" {
│
╵
ERRO[0129] 1 error occurred:
	* exit status 1

刚好这例子中

  • .tf resource / address 已经有了,就是 module.network.azurerm_subnet.subnet[0]
  • remote infra 也已经存在, ID "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1"

到 terraform registry 中的各个 resource 文件下查询 import 语法,例如 azurerm_subnet 底下有 import 语法

  • 由於各家公有云的 API 设计本质上就不同,因此不同公有云的 import syntax 也不同,每次记得来 registry 文件查询
  • 根据文件的 import 语法,换成上面 error message 提供的 id
  • error message 这麽刚好吗?这是有先配好的,也就是预期 id / name 重复的 resource create error 时,要提供可以 import 的 id 在 error message 中
  • 一样记得 bash 中,该 double quote 记得要 quote
  • 一样记得我们是用 terragrunt shim layer 呼叫 terraform 的指令
terraform import azurerm_subnet.exampleSubnet /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/virtualNetworks/myvnet1/subnets/mysubnet1

cd azure/foundation/compute_network

terragrunt import "module.network.azurerm_subnet.subnet[0]" "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1"

module.network.azurerm_subnet.subnet[0]: Importing from ID "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1"...
module.network.azurerm_subnet.subnet[0]: Import prepared!
  Prepared azurerm_subnet for import
module.network.azurerm_subnet.subnet[0]: Refreshing state... [id=/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

显示 import 成功

  • 一样养成习惯,每次执行 state 变更後,务必检查 state
  • state list 检查 address 状态
  • plan 检查 .tf 与 state 是否符合
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

terragrunt plan

Changes to Outputs:
  ~ vnet_subnets = [
      - null,
      + "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-1",
        "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Network/virtualNetworks/acctvnet/subnets/dev-2",
        # (1 unchanged element hidden)
    ]

You can apply this plan to save these new output values to the Terraform
state, without changing any real infrastructure.

plan 显示剩下唯一有差异的地方是 output 的值,我们进行 apply 来更新这个 output

  • state 变更後,有可能会影响到其他的 state,也就是会有连锁反应
  • 这边只是影响一个 output,没什麽差别,但在复杂的专案中,要特别小心
terragrunt apply

Practical terraform import

上面我们直接使用 state rm 後的例子来做 import 示范,但实务上会更接近

  • 去 terraform registry document 找 import syntax,包含 id 或 path 的定位路径
  • 由於不一定 import state 会与 .tf resource 的设定完全符合,一般来说我们会在 import 後 plan 一次
  • 根据 plan 有所出入,调整 .tf resource 直到符合 state (也就是 plan 时计算结果是 no changes)
  • 手动完成 .tf resource 与 remote resource 的对照

multiple collaborater workflow

与前面一样,更改 state 会有多人协作的问题,这边操作流程类似。如果团队在专案途中开始导入 terraform 的话,不妨参考一下这个流程

  • master 是 auto plan + auto apply
  • 开新的 branch,为 remote resource 增加 .tf resource,对应 remote resource
  • 开 PR,进行 code review
  • review 完成後,不要 merge 进 master 造成 auto apply failure,而是标上 do-not-merge 与 manual-operation-required 等 tag
  • notify team 即将要进行手动的 terraform import,告知影响的 module,请团队成员不要进来 plan / apply
  • 开始手动操作 terraform import
  • 完成 import 後,手动检查 state list 与 terraform plan result
  • 确定 .tf 与 state 与 remote resource 三方达成一致
  • merge PR 到 master
  • master auto plan 会显示 no changes

When you need import

所以,何时需要 import

一个是团队成员中有 state rm 狂人,或是有人搞砸弄坏 state 被迫上来修

  • 实际操作流程如 state rm 再 import 例子

一个是上面第二个例子,就是逐渐导入 terraform 的过程,如果有既有的 resource,这样会常常用到 import,请小心操作

另外一个,也算是常见的例子,就是被中断的 terraform workflow

  • 可能是 terraform apply 途中网路断线,被迫停止
  • 此时 public cloud API 已经打出去了,但在等待 resource 创建完成需要时间,卡在中途
    • 有 .tf resource,apply 到一半
    • 有 remote resource
    • state 尚未更新,也就是缺 state
  • 这时的修复流程可能会用到 import
    • 首先透过 az-cli 或是 web console,先检查 remote resource 实际状况到底跟 .tf 差多少
    • force-unlock state lock,因为 apply 到一半没有 state 收尾,仍然是 lock 状态(unlock 之前最好跟 team member 确认一下)
    • 取得 id,进行 terraform import 修复
  • 接续 apply 的工作

<<:  Day23-资料操作

>>:  【第二十三天 - DFS 题目分析】

Day.29 其他树的介绍

树有非常多变型,下面是Wiki的截图 以下简单介绍几种常听到的~ AVL Trees、Red Bla...

DAY 23- HTTPS、TLS/ SSL

「我们的连结够安全吗。」 HTTP(HyperText Transfer Protocol) 超文本...

Day_26 vsftpd

今天介绍另外一个古老的文件技术FTP(File Transfer Protocol)。建立一个档案s...

Day 18: 人工神经网路初探 前馈神经网路

Feedforward 前馈神经网路 前馈神经网路是一种neuron之间的连接并不形成循环的人工智...

[Day09] 从 appsettings.json 取得设定

昨天我们新增了一个 UserServiceWithFile 操作本地端档案来管理使用者资料,而档案的...