1. 概要
resourceとdataの根本的な違い- それぞれがどのような操作をTerraformに指示するか
- 典型的なユースケースと使い分けの判断基準
- よくある誤用パターンと正しい使い方
- 組み合わせ使用のベストプラクティス
Terraformには「リソースを作る」resourceブロックと、「既存リソースを参照する」dataブロックがあります。この2つの使い分けを正確に理解することが、Terraformコードの品質を高める上で非常に重要です。
2. 根本的な違い
| 比較 | resource | data(データソース) |
|---|---|---|
| 目的 | リソースを作成・管理する | 既存リソースを参照する |
| 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ブロック — 既存リソースの参照
dataはTerraform管理外の既存リソースを参照します。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. 関連記事
- data(データソース)の使い方 — dataブロックの詳細
- resourceブロックの使い方 — resourceブロックの詳細
- import ブロック — 既存リソースをresource管理下に移行する
- state管理とは — resourceとstateの関係
- required_providers と provider — 設定方法
- locals(ローカル値)— DRYなコードを書く
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