手动编辑 tfstate(s3后端编辑)

terraform apply 的状态管理通过 tfstate 文件进行,这里会将对服务器资源的更改和结果保存为状态文件。如果 tfstate 的状态与 tf 文件的内容不同,执行 terraform plan 将显示状态差异。

基本上,tfstate文件不需要手动更改,但在尝试将现有服务器资源的配置内容添加到terraform管理之后,有时候不得不手动进行更改。

(例如:IAM Group、Policy等信息,如果没有保存在tfstate中,则所有这些内容都将被视为新建处理。如果您在tf文件中编写与现有资源相同的配置,然后执行terraform apply命令,将会出现409错误。)

在这份文件中,我会写关于如何手动编辑 tfstate 的步骤。

tfstate 格式 – 通用(第四版)

总的来说,我会简单介绍一下tfstate的数据格式。

tfstate的表达形式是JSON格式。

尽管公式文档中没有太多描述,但是在0.12.x版本中,格式(版本4)如下所示。

根据 Terraform 的版本,tfstate 文件的版本也会有所不同,并且它们会微妙地影响到应该进行的描述。

{
  "version": 4,
  "terraform_version": "0.12.18",
  "serial": 679,
  "lineage": "617d8489-6973-bac0-2750-3457992f99db",
  "outputs": {
    "security_groups": {
      "value": {
        "sada": [
          "sg-xxxxxxxx",
          "sg-xxxxxxxx"
        ],
      },
      "type": [
        "object",
        {
          "sada": [
            "tuple",
            [
              "string",
              "string"
            ]
          ]
        }
      ]
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_security_group",
      "name": "sada",
      "provider": "provider.aws",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:xxxxxx.....",
(snip.)
        }
      ]
    }
  ]
}

state是tfstate文件本身的格式号,terraform_version是运行的terraform版本,serial是tfstate的更改次数(每次进行terraform apply时会递增),lineage是在执行terraform init时分配的UUID。

输出中,outputs字段保存了执行terraform apply后的输出结果,而resources字段保存了实际应用配置的资源状态。

此外,我认为阅读用 Go 编写的源代码是最快的方式来了解其它数据定义是什么样的。

当您手动编辑tfstate时,基本上会对资源内容进行追加、修改和删除。

tfstate格式 – 资源(第4版)

资源的格式如下,以数组的形式表示每个资源。

  "resources": [
    {
      "mode": "managed",
      "type": "aws_security_group",
      "name": "sada",
      "provider": "provider.aws",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:xxxxxx.....",
(snip.)
        }
      ]
    }
  ]

mode参数通常用来控制所管理的服务器资源或数据资源,type参数用来指明目标资源的名称,name参数用来给资源指定一个名称,provider参数则指定了所使用的资源提供者(比如aws、azurerm等)。

基本上,你會在 instances.attributes 中進行編輯,因為其中的內容代表了每個單一資源的設定信息。

例如,对于 aws_security_group,应该在属性中设置以下项。

    • arn

 

    • id

 

    • name

 

    • vpc-id

 

    • ingress

 

    • egress

 

    etc…

在此文档中,并未详细说明应设置各资源的属性。

以下是在将S3指定为后端时编辑tfstate的步骤。

编辑 S3 后端的 tfstate 的步骤。

我认为并不是没有直接修改S3上文件的方法,但是直接修改的风险可能很高。因此,我在这里将介绍以下步骤。

将后端临时切换到本地。

terraform {
#  backend "s3" {
#    bucket                  = "sada-terraform-state"
#    key                     = "tfstate.json"
#    region                  = "ap-northeast-1"
(snip.)
#  }
  backend "local" {
    path = "terraform.tfstate"
  }
}

初始化Terraform

切换后端后执行 terraform init 命令时,会显示一个询问消息,询问是否将当前的 tfstate 复制到切换后的后端。

Terraform detected that the backend type changed from "s3" to "local".
Do you want to copy existing state to the new backend?
(snip.)

在这里键入“是”并切换到后端时,tfstate 文件将被复制到切换的后端。

因为在这里将后端切换到本地,所以文件会保存在 terraform.tfstate 中。

3. 修改 tfstate 和 tf 文件

对本地保存的 tfstate 进行修改。

以下是使用terraform import方法进行更改的步骤说明。

3.1. 土地整形导入

这是一个用于获取现有资源信息并将其反映到 tfstate 的命令。

您可以执行以下命令,将最新的资源状态导入到 tfstate 中。

terraform import -state=terraform.tfstate aws_security_group.sada sg-xxxxxxxx

使用terraform import可以方便地获取资源状态,虽然并非仅仅最新的资源状态采用手动编辑 tfstate 的动机。

3.2.展示Terraform状态

可以通过使用 terraform state show 命令来查看 tfstate 中的配置内容。

使用这个方法,确认 tfstate 是否达到了预期的状态。

terraform state show -state=terraform.tfstate aws_security_group.sada
# aws_security_group.sada:
resource "aws_security_group" "sada" {
    arn                    = "arn:aws:ec2:ap-northeast-1:xxxxxx....."
(snip.)

}

修改、创建、删除3.3.tf文件。

根据以上内容,在tf文件中定义所需的信息。

在使用terraform plan和apply时,请确认是否达到了预期的差异状态。

完成修改后,请执行terraform plan命令来确认变更已成功反映。

如果需要反映,请执行terraform apply。

将后端还原到S3中。

如果没有问题,将后端再次返回到s3。

terraform {
  backend "s3" {
    bucket                  = "sada-terraform-state"
    key                     = "tfstate.json"
    region                  = "ap-northeast-1"
(snip.)
  }
#  backend "local" {
#    path = "terraform.tfstate"
#  }
}

6. 初始化terraform

当将 backend 切换回 S3 并执行 terraform init 时,您将被询问是否要将本地的 tfstate 文件复制到 S3 中,请输入“是”(yes)。

Terraform detected that the backend type changed from "local" to "s3".
Do you want to copy existing state to the new backend?
(snip.)

7.计划执行terraform

为了确认在将后端恢复到 S3 后是否与意图的差异相符,我们可以使用 terraform plan 进行确认。

这样一来,所有工作都完成了。