LESSON 30分

プロバイダとState管理

ストーリー

「Terraformの最も重要な概念の1つがStateだ」

木村先輩が terraform.tfstate ファイルを開いた。

「Terraformは『コードに書いたあるべき姿』と 『実際のクラウド上の状態』を比較して差分を計算する。 その『実際の状態』を記録しているのがStateファイルだ」

「これを壊したらどうなるんですか?」

「Terraformがリソースを認識できなくなる。 最悪、同じリソースを二重に作ったり、 既存のリソースを消せなくなったりする。 Stateの管理は生命線だ」


プロバイダ(Provider)

プロバイダとは

プロバイダは、TerraformがクラウドサービスのAPIと通信するためのプラグインです。

プロバイダの役割

  Terraform コード (.tf)
       │
       ▼
  ┌──────────────┐
  │  Terraform    │
  │  Core         │
  └──────┬───────┘
         │
    ┌────┴────┐
    ▼         ▼
┌──────┐  ┌──────┐
│ AWS   │  │ GCP   │
│Provider│  │Provider│
└──┬───┘  └──┬───┘
   ▼         ▼
  AWS API   GCP API

プロバイダの設定

hcl
# providers.tf
terraform {
  required_version = ">= 1.7.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"        # 5.x 系の最新
    }
  }
}

# AWSプロバイダの設定
provider "aws" {
  region = "ap-northeast-1"

  default_tags {
    tags = {
      ManagedBy   = "terraform"
      Project     = "my-project"
      Environment = var.environment
    }
  }
}

バージョン制約

制約式意味
= 5.0.0完全一致5.0.0 のみ
>= 5.0以上5.0, 5.1, 6.0 ...
~> 5.0パッチバージョンのみ許容5.0.x
~> 5.0.0マイナーバージョンのみ許容5.0.0 〜 5.0.x
>= 5.0, < 6.0範囲指定5.x 系

複数リージョンの使用(エイリアス)

hcl
# 東京リージョン(デフォルト)
provider "aws" {
  region = "ap-northeast-1"
}

# バージニアリージョン
provider "aws" {
  alias  = "virginia"
  region = "us-east-1"
}

# バージニアのリソース
resource "aws_s3_bucket" "logs" {
  provider = aws.virginia
  bucket   = "my-logs-bucket-us"
}

State(状態管理)

Stateとは

TerraformのStateは、管理しているリソースの現在の状態を記録するJSONファイルです。

Stateの役割

┌───────────┐     ┌───────────┐     ┌───────────┐
│  .tf ファイル │     │   State    │     │  実際の     │
│ (あるべき姿) │     │ (記録状態)  │     │ クラウド状態 │
└──────┬────┘     └──────┬────┘     └──────┬────┘
       │                  │                  │
       └────────┬─────────┘                  │
                │                            │
                ▼                            │
         terraform plan                      │
         (差分計算)  ←───────────────────────┘
                │
                ▼
         terraform apply
         (差分適用)

Stateファイルの中身

json
{
  "version": 4,
  "terraform_version": "1.7.0",
  "resources": [
    {
      "type": "aws_instance",
      "name": "web",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "attributes": {
            "id": "i-0abc123def456",
            "ami": "ami-0abcdef1234567890",
            "instance_type": "t3.micro",
            "public_ip": "54.123.45.67"
          }
        }
      ]
    }
  ]
}

ローカルState vs リモートState

ローカルState(デフォルト)

ローカルState

my-project/
├── main.tf
├── terraform.tfstate        ← ローカルファイル
└── terraform.tfstate.backup

問題点:
- チーム開発で共有できない
- 誤って削除するリスク
- 同時実行で競合する可能性

リモートState(推奨)

リモートState (S3 + DynamoDB)

┌──── 開発者A ────┐     ┌──── 開発者B ────┐
│ terraform apply  │     │ terraform apply  │
└────────┬────────┘     └────────┬────────┘
         │                       │
         └───────────┬───────────┘
                     ▼
            ┌───── S3 ──────┐
            │  tfstate ファイル │
            │  (暗号化保存)    │
            └───────────────┘
                     │
            ┌── DynamoDB ──┐
            │  状態ロック     │
            │  (排他制御)    │
            └──────────────┘

リモートStateの設定

hcl
# backend.tf
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "production/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

S3バケットとDynamoDBテーブルの事前作成

hcl
# state-backend/main.tf(Stateバックエンド自体のTerraform)
resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-terraform-state-bucket"

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_dynamodb_table" "terraform_lock" {
  name         = "terraform-state-lock"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

State操作コマンド

コマンド用途
terraform state list管理中のリソース一覧
terraform state show aws_instance.webリソースの詳細表示
terraform state mvリソースの名前変更/移動
terraform state rmStateからリソースを削除(実体は残る)
terraform import既存リソースをStateに取り込む

import の例

bash
# 手動で作成したEC2インスタンスをTerraform管理下に置く
terraform import aws_instance.web i-0abc123def456

Stateのベストプラクティス

プラクティス説明
リモートState必須チーム開発では必ずS3等のリモートバックエンドを使用
State暗号化S3の暗号化を有効にする
ロック有効化DynamoDBで排他制御を行う
バージョニングS3バージョニングで誤操作に備える
直接編集禁止StateファイルをテキストエディタなどでSTATE直接編集しない
環境分離staging/production でStateファイルを分ける

まとめ

ポイント内容
プロバイダクラウドAPIとの通信プラグイン、バージョン固定推奨
Stateリソースの現在状態を記録するファイル
リモートStateS3 + DynamoDB でチーム共有と排他制御
import既存リソースをTerraform管理下に取り込む

チェックリスト

  • プロバイダの設定とバージョン制約を書ける
  • Stateの役割と重要性を説明できる
  • ローカルStateとリモートStateの違いを理解した
  • S3 + DynamoDB でリモートStateを設定できる

次のステップへ

次のセクションでは、変数とモジュールについて学びます。 Terraformコードの再利用性と保守性を高める方法をマスターしましょう。


推定読了時間: 30分