🗽

terraform.tfstateを読んでみる

2023/06/17に公開

はじめに

terraformのリソースの状態はterraform.tfstateファイルに保存されています。
いままでスルーしてきたのですが、今回はこれを読んでみようと思います。

検証方法として、applyなどの状態変化後のtfstateを見ていこうと思います。

環境

terraform 1.4.6

題材

これをapplyしました

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.65.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
  default_tags {
    tags = {
      env       = "test"
      provision = "terraform"
    }
  }
}

resource "aws_s3_bucket" "s3" {
}

検証

apply後のtfstate

はこちら

terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.4.6",
  "serial": 1,
  "lineage": "d16af0bd-c329-ff5e-25d3-ae6de0058ef2",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "aws_s3_bucket",
      "name": "s3",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "acceleration_status": "",
            "acl": null,
            "arn": "arn:aws:s3:::terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx",
            "bucket": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx",
            "bucket_domain_name": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx.s3.amazonaws.com",
            "bucket_prefix": "terraform-",
            "bucket_regional_domain_name": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx.s3.ap-northeast-1.amazonaws.com",
            "cors_rule": [],
            "force_destroy": false,
            "grant": [
              {
                "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                "permissions": [
                  "FULL_CONTROL"
                ],
                "type": "CanonicalUser",
                "uri": ""
              }
            ],
            "hosted_zone_id": "xxxxxxxxxxxx",
            "id": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx",
            "lifecycle_rule": [],
            "logging": [],
            "object_lock_configuration": [],
            "object_lock_enabled": false,
            "policy": "",
            "region": "ap-northeast-1",
            "replication_configuration": [],
            "request_payer": "BucketOwner",
            "server_side_encryption_configuration": [
              {
                "rule": [
                  {
                    "apply_server_side_encryption_by_default": [
                      {
                        "kms_master_key_id": "",
                        "sse_algorithm": "AES256"
                      }
                    ],
                    "bucket_key_enabled": false
                  }
                ]
              }
            ],
            "tags": null,
            "tags_all": {
              "env": "test",
              "provision": "terraform"
            },
            "timeouts": null,
            "versioning": [
              {
                "enabled": false,
                "mfa_delete": false
              }
            ],
            "website": [],
            "website_domain": null,
            "website_endpoint": null
          },
          "sensitive_attributes": [],
          "private": "xxxxxxxxxxxx"
        }
      ]
    }
  ],
  "check_results": null
}

よくわかりません。
attributesはリソースのパラメータでしょう、今後は省略します。

destroy後のtfstate

はこちら

terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.4.6",
  "serial": 3,
  "lineage": "d16af0bd-c329-ff5e-25d3-ae6de0058ef2",
  "outputs": {},
  "resources": [],
  "check_results": null
}

destroyしたためでしょう、resourcesの値がなくなっています。
またserialは2インクリメントされ、lineageは変化していません。

再apply後のtfstate

はこちら

{
  "version": 4,
  "terraform_version": "1.4.6",
- "serial": 1,
+ "serial": 5,
  "lineage": "d16af0bd-c329-ff5e-25d3-ae6de0058ef2",
  "outputs": {},
  "resources": [
  // 略
  ],
  "check_results": null
}

再びserialは2インクリメントされ、lineageは変化していません。

outputをapply後のtfstate

このように追加しました

resource "aws_s3_bucket" "s3" {
}

+output "s3_bucket_domain_name" {
+  value = aws_s3_bucket.s3.bucket_domain_name
+}

tfstateは

{
  "version": 4,
  "terraform_version": "1.4.6",
  "serial": 6,
  "lineage": "d16af0bd-c329-ff5e-25d3-ae6de0058ef2",
  "outputs": {
    "s3_bucket_domain_name": {
      "value": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx.s3.amazonaws.com",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_s3_bucket",
      "name": "s3",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
// 略

outputsに値が格納され、serialは1インクリメントされました。
ここは1なんですね

dataをapply後のtfstate

適当に転がっていたEC2をdataで追加してみます。

resource "aws_s3_bucket" "s3" {
}

+data "aws_instance" "foo" {
+  instance_id = "i-xxxxxxxxxxx"
+}

tfstateは

{
  "version": 4,
  "terraform_version": "1.4.6",
  "serial": 7,
  "lineage": "d16af0bd-c329-ff5e-25d3-ae6de0058ef2",
  "outputs": {
    "s3_bucket_domain_name": {
      "value": "terraform-xxxxxxxxxxxxxxxxxxxxxxxxxx.s3.amazonaws.com",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "data",
      "type": "aws_instance",
      "name": "foo",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
// 略
    {
      "mode": "managed",
      "type": "aws_s3_bucket",
      "name": "s3",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
// 略

modedataであるEC2リソースが追加され、serialに1インクリメントされました。
ここも1です。

まとめ

検証の結果からtfstateの要素をまとめてみました。

seriallineage

  • serial:tfstateの変更回数。
    output,dataを追加した場合は1,applyで変更した場合は2インクリメントされました。
  • lineage:環境に対して払い出されるUUID。
    最初のterraform init時に確定され、applyしても変化しません。

この2つでterraformは状態を管理していると思われます。

2つについて説明しているディスカッションがこちら
https://discuss.hashicorp.com/t/terraform-state-schema/48660/2

outputs

tfファイルのoutputブロックの値が格納されるようです。

resources

リソースごとの情報が格納されるようです。
modeにはmanageddataが格納される。
terraformで管理しているか、外部リソースかで区別しているのだと思います。

https://developer.hashicorp.com/terraform/tutorials/state/

attributes

リソースの情報が格納されているようです。
何が入るかはドキュメントのArgument Reference,Attributes Referenceを参照すればよいはず。
以下はs3のドキュメントです。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket

check_results

リソースが想定通りの動作をするかテストを行う、checkブロックがterrform 1.5で追加されました。
そのテスト結果が格納されるそうです。

https://developer.hashicorp.com/terraform/tutorials/configuration-language/checks

今回はバージョン1.4を使用したため未検証ですが、いずれ試してみます。

所感

わからないことはまだまだ多いですが、
serialがstate毎に変化するという点から、バックエンドでバージョン管理を行うのが大事なんだなあ
とざっくり思いました。

次回はtfstate周りのcliを試してみたいと思います。

参考

https://qiita.com/moaikids/items/d11dee96c8d68262098b
https://developer.hashicorp.com/terraform/tutorials/state

Discussion