初次认识状态文件

Terraform是如何管理资源的状态

前面通过在

这篇文章中,我们使用terraform实践了基于vmware的虚拟机编排流程;

那么已经知道,在执行 terraform init 之后,Terraform 会将依赖的插件下载到本地 .terraform 目录。

(base) ➜  vmware git:(develop) ✗ tree -aL 5                                                       
.
├── .envfile
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── vsphere
├── .terraform.lock.hcl
├── main.tf
├── output.tf
├── startup.sh
└── variables.tf

在执行 terraform apply 之后,Terraform 会使用 terraform.tfstate 文件存储资源的信息。并且新建 .terraform.tfstate.lock.info 锁定资源,避免多个 Terraform 同时使用一个状态文件。

(base) ➜  vmware git:(develop) ✗ tree -aL 5

.
├── .envfile
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── vsphere
├── .terraform.lock.hcl
├── .terraform.tfstate.lock.info
├── main.tf
├── output.tf
├── startup.sh
├── terraform.tfstate
└── variables.tf

5 directories, 8 files

查看 .terraform.tfstate.lock.info 文件可以从中提取执行者信息

{"ID":"59479f71-896d-eb94-3528-cdfc6740fbd0","Operation":"OperationTypeApply","Info":"","Who":"bohai@JiaJia.local","Version":"1.5.7","Created":"2023-11-11T02:57:52.492675Z","Path":"terraform.tfstate"}%   

查看 terraform.tfstate 可以得知其本身是一个 JSON 文件,存储了资源的 ID 、状态等信息,格式如下:

(base) ➜  vmware git:(develop) ✗ cat terraform.tfstate           
{
  "version": 4,
  "terraform_version": "1.5.7",
  "serial": 2,
  "lineage": "d38d6fdb-6e78-61d4-4f02-147191a1d974",
    "Linux-VM": {
      "value": [
        "terraform-s3-01"
      ],
......省略大部分内容.....
    "Linux-guest-ip": {
      "value": [
        [
          "192.168.60.32",
          "fda9:8b2a:a222:0:250:56ff:fea5:e45",
          "fe80::250:56ff:fea5:e45"
        ]
......省略大部分内容.....
}

该文件存在一个资源的备份功能,若在任务执行后,未删除 terraform.tfstate 文件。则会在重复执行时覆盖掉原有创建的资源。

通过状态文件销毁资源

借助 terraform.tfstate 文件执行 terraform destroy 之后,还可将状态文件中存储的资源进行销毁。

(base) ➜  vmware git:(develop) ✗ terraform destroy
data.vsphere_datacenter.dc: Reading...
......省略大部分内容......
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

......省略大部分内容......

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

......省略大部分内容......

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

......省略大部分内容......


Destroy complete! Resources: 1 destroyed.

执行后,最后看到 Destroy complete! Resources: xxx destroyed. 则说明之前创建的资源既已销毁。

在销毁后,Terraform 会新建一个 terraform.tfstate.backup 文件,备份销毁的资源信息状态。

通过备份状态文件恢复资源

在Terraform中,资源能被销毁,既也能被恢复。 恢复的方法也很简单,只需要将 terraform.tfstate.backup 文件内容覆盖到 terraform.tfstate 中,重新apply即可。

(base) ➜  vmware git:(develop) ✗ cp terraform.tfstate terraform.tfstate.bak       
(base) ➜  vmware git:(develop) ✗ terraform apply                                              
......省略大部分内容......
Note: Objects have changed outside of Terraform
......省略大部分内容......
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
  ~ Linux-guest-ip = [
      - [
          - "192.168.60.11",
          - "fda9:8b2a:a222:0:250:56ff:fea5:cfa1",
          - "fe80::250:56ff:fea5:cfa1",
        ],
    ]
......省略大部分内容......

总结

至此,我们已经了解了terraform如何来管理任务资源、资源的状态文件、资源的销毁以及恢复。具体的细节没有深究太多,简单点就是 Terraform 使用 JSON文件存储资源的状态,默认存储在本地目录下。

使用minio存储状态文件

如果在一个团队、Jenkins、GitHub Actions 各种集成CI平台中,如何持久化存储 Terraform 的状态呢?持久化状态也就是需要将上面的 JSON 文件数据存储在某一个远端持久化服务中。Terraform 支持很多种后端存储,下面是从Terraform 官网获取的一个常用的Backend 列表:

  • etcd
  • etcdv3
  • http
  • kubernetes
  • oss (阿里云对象存储)
  • cos (腾讯云对象存储)
  • s3 (兼容Minio存储)

Terraform 使用 Backend 模块来处理状态的存储。在 variables.tf 文件中,只需要添加一个 backend ,填上参数即可使用远端存储状态。下面使用s3协议的minio来做演示。

(base) ➜  vmware git:(develop) ✗ cat variables.tf|head -40
terraform {
  backend "s3" {

    # 存储路径/文件名称(建议额外通过程序参数传入,避免覆盖状态文件)
    key      = "terraform/tf-cd"
    # 桶名称
    bucket   = "app-storage"
    # minio服务地址
    endpoint = "http://xxx.xxx.xxx.xxx:9000"
    # 修改为实际内容
    access_key = "xxx"
    secret_key = "xxx"

    # 无需修改
    region = "main"
    force_path_style = true
    skip_credentials_validation = true
    skip_metadata_api_check = true
    skip_region_validation = true
  }
}

之后重新初始化Terraform

(base) ➜  vmware git:(develop) ✗ terraform init
Initializing the backend...

# 若本地存在状态文件,则会将其拷贝至远端存储中
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the newly
  configured "s3" backend. Do you want to copy this state to the new "s3"
  backend? Enter "yes" to copy and "no" to start with an empty state.

# 键入yes开始
  Enter a value: yes

# 初始化成功
Terraform has been successfully initialized!

此时,在 terraform apply 之后,在对象存储中,就可以看到状态文件:

参考

Last modification:November 11, 2023
如果觉得我的文章对你有用,请随意赞赏