data vs resource 違い — 参照と作成の使い分け完全ガイド

1. 概要

  • resourcedataの根本的な違い
  • それぞれがどのような操作をTerraformに指示するか
  • 典型的なユースケースと使い分けの判断基準
  • よくある誤用パターンと正しい使い方
  • 組み合わせ使用のベストプラクティス

Terraformには「リソースを作るresourceブロックと、「既存リソースを参照するdataブロックがあります。この2つの使い分けを正確に理解することが、Terraformコードの品質を高める上で非常に重要です。


2. 根本的な違い

比較resourcedata(データソース)
目的リソースを作成・管理する既存リソースを参照する
stateへの影響stateに追加されるstateに追加されない
destroy時リソースが削除される何も起きない
変更時リソースが更新・再作成される参照値が更新されるだけ

3. resourceブロック — 作成と管理

resourceはTerraformがライフサイクルを管理するリソースを定義します。applyで作成され、destroyで削除されます。

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

# Terraform が作成・管理するS3バケット
resource "aws_s3_bucket" "app_data" {
  bucket = "${var.environment}-myapp-data"

  tags = {
    Name        = "${var.environment}-myapp-data"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# Terraform が作成・管理するセキュリティグループ
resource "aws_security_group" "web" {
  name        = "${var.environment}-web-sg"
  description = "Web server security group"

  tags = {
    Name        = "${var.environment}-web-sg"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

4. dataブロック — 既存リソースの参照

dataTerraform管理外の既存リソースを参照します。stateに影響せず、destroyしても削除されません。

# 最新のAmazon Linux 2023 AMIを動的に取得(Terraform管理外)
data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

# 既存のVPCを参照(手動作成済み or 別のTerraformで管理)
data "aws_vpc" "existing" {
  filter {
    name   = "tag:Name"
    values = ["${var.environment}-vpc"]
  }
}

# 取得したデータを使ってリソースを作成
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux_2023.id  # dataから参照
  instance_type = "t3.micro"
  subnet_id     = data.aws_vpc.existing.id           # dataから参照

  root_block_device {
    volume_size = 20
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${var.environment}-web"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

5. 使い分けの判断基準

このリソースをTerraformで作成・削除したいか?
  ↓
  YES → resource ブロック
  NO  → data ブロック

具体的に判断する際の問いかけ:

「terraform destroy を実行したとき、このリソースも消えてよいか?」
  YES → resource
  NO  → data

6. よくある誤用パターン

❌ パターン1: AMI IDをハードコードしてしまう

# 悪い例: AMI IDをハードコード
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"  # リージョンやバージョンで変わる
  instance_type = "t3.micro"
}
# 良い例: data で動的に取得
data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"
}

❌ パターン2: 共有リソースをresourceで作ってしまう

# 悪い例: 複数チームで共有するVPCをresourceで作成
# → destroyで削除されてしまう
resource "aws_vpc" "shared" {
  cidr_block = "10.0.0.0/16"
}
# 良い例: 共有VPCはdataで参照のみ
data "aws_vpc" "shared" {
  filter {
    name   = "tag:Name"
    values = ["shared-vpc"]
  }
}

7. resourceとdataを組み合わせる

実際のコードではresourceとdataを組み合わせて使うのが一般的です。

# 外部管理のリソースはdataで参照
data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

data "aws_subnets" "private" {
  filter {
    name   = "tag:Type"
    values = ["private"]
  }
  filter {
    name   = "tag:Environment"
    values = [var.environment]
  }
}

# このTerraformで管理するリソースはresourceで定義
resource "aws_instance" "app" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"
  subnet_id     = data.aws_subnets.private.ids[0]

  root_block_device {
    volume_size = 20
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${var.environment}-app"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

8. 関連記事


9. まとめ

  • resourceはTerraformが作成・更新・削除を管理するリソース
  • data既存リソースを読み取るだけで、stateや実リソースに影響しない
  • terraform destroyで消えてよいか?」が使い分けの判断基準
  • AMI IDのハードコードや共有リソースのresource定義は典型的な誤用
  • 実際のコードではdataでAMI・VPC・サブネットを参照し、resourceでEC2・SG等を管理するのが定番パターン

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/data-sources