6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform 入門まとめ: 基本文法から AWS 実例、`data` / `locals` / `output` / ファイル分割まで一気に整理

6
Last updated at Posted at 2026-04-11

Terraform 入門まとめ: 基本文法から AWS 実例、data / locals / output / ファイル分割まで一気に整理

Terraform を学び始めると、最初は次のような疑問が連続で出てきます。

  • resource "aws_instance" "web""web" は何か
  • local_file は何か
  • dataresource は何が違うのか
  • locals は何に使うのか
  • .tf ファイル間で import は必要なのか
  • main.tf には何を書くべきか
  • output は何のためにあるのか

この記事では、そうした疑問を Terraform の基本構造から AWS 実例までつなげて まとめます。
Terraform 初学者が「全体像」をつかめるように、できるだけ実例ベースで整理しています。


Terraform とは

Terraform は、インフラをコードで定義して作成・管理するための IaC ツールです。
AWS、GCP、Azure などのクラウドや、SaaS、ローカル環境など、さまざまな対象をコードで管理できます。

Terraform の設定は主に HCL(HashiCorp Configuration Language) という記法で書きます。

Terraform のコードは、ざっくりいうと次の部品で構成されます。

  • terraform
  • provider
  • variable
  • locals
  • data
  • resource
  • output

まずはそれぞれを順番に見ていきます。


1. Terraform の基本構文

Terraform の設定は ブロック の集まりです。

たとえば最小構成はこんな形です。

terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

provider "local" {}

resource "local_file" "example" {
  filename = "hello.txt"
  content  = "Hello Terraform"
}

このコードでは、terraform apply を実行するとローカルに hello.txt が作成されます。

1-1. ブロックの基本形

Terraform のブロックはだいたい次の形で書きます。

ブロック種別 "リソース種別" "Terraform 内でのリソース名" {
  引数名 = 
}

たとえば:

resource "local_file" "example" {
  filename = "hello.txt"
}

これは

  • ブロック種別: resource
  • リソース種別: local_file
  • リソース名: example

です。


1-2. 値の書き方

Terraform では次のような値が使えます。

文字列・数値・真偽値

name    = "web-server"
port    = 8080
enabled = true

リスト

ports = [80, 443, 8080]

マップ

tags = {
  Environment = "dev"
  Owner       = "team-a"
}

複数行文字列

content = <<EOF
line1
line2
line3
EOF

2. local_file とは何か

Terraform の学習で最初によく出てくるのが local_file です。

resource "local_file" "example" {
  filename = "hello.txt"
  content  = "Hello Terraform"
}

local_file は、local プロバイダが提供するリソース型 です。
AWS の EC2 のようなクラウドリソースではなく、Terraform を実行しているマシン上にローカルファイルを作るためのリソース です。

つまりこのコードは、

  • hello.txt というファイルを作る
  • 中身に Hello Terraform を書く

という意味になります。

2-1. 何に使うのか

local_file は主に次のような用途で使われます。

  • Terraform の学習
  • 設定ファイルの生成
  • 確認用ファイルの出力
  • テンプレートから .env や JSON を作る

resource "local_file" "env_file" {
  filename = ".env"
  content  = <<EOF
APP_NAME=myapp
APP_ENV=local
APP_DEBUG=true
EOF
}

3. ラベルはなぜ必要なのか

Terraform で最初に混乱しやすいのがこれです。

resource "local_file" "example" {
  filename = "hello.txt"
  content  = "Hello Terraform"
}

この "example" は何かというと、Terraform 内でそのリソースを識別するための名前 です。

3-1. ラベルの役割

Terraform はリソースを 型 + 名前 で管理します。

この場合は:

  • 型: local_file
  • 名前: example

です。

つまり Terraform はこのリソースを local_file.example として扱います。

参照例

output "file_name" {
  value = local_file.example.filename
}

ここでの local_file.example.filename は、

  • local_file = リソース型
  • example = ラベル
  • filename = 属性

という意味です。

3-2. ラベルはなくてもいいのか

resource では 必要です。なくせません。

これは OK です。

resource "local_file" "example" {
  filename = "hello.txt"
}

これは NG です。

resource "local_file" {
  filename = "hello.txt"
}

resource ブロックは構文上、基本的に次の形が必要です。

resource "リソースタイプ" "ローカル名" {
  ...
}

3-3. ブロックによってラベル数は違う

ラベルなし

terraform {
  required_version = ">= 1.0"
}

locals {
  app_name = "demo"
}

1つラベルあり

variable "app_name" {
  type = string
}

output "result" {
  value = "ok"
}

2つラベルあり

resource "local_file" "example" {
  filename = "a.txt"
}

4. AWS の実例で Terraform を見る

ここからは AWS で見ていきます。

最小の EC2 作成例です。

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

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

resource "aws_instance" "web" {
  ami           = "ami-xxxxxxxxxxxxxxxxx"
  instance_type = "t3.micro"

  tags = {
    Name = "terraform-web"
  }
}

4-1. これを分解すると

terraform {}

Terraform 本体の設定です。
ここでは AWS プロバイダを使う宣言をしています。

provider "aws" {}

どのクラウドを使うか、その接続設定を書きます。
この例では東京リージョンを指定しています。

resource "aws_instance" "web" {}

AWS の EC2 インスタンスを作る定義です。

  • aws_instance = EC2 インスタンスというリソース型
  • web = Terraform 内での名前

つまり aws_instance.web として参照できます。


5. variable で可変部分を外出しする

AMI ID やインスタンスタイプを毎回固定値で書くと使い回しにくいので、variable を使います。

variable "aws_region" {
  type    = string
  default = "ap-northeast-1"
}

variable "ami_id" {
  type = string
}

variable "instance_type" {
  type    = string
  default = "t3.micro"
}

provider "aws" {
  region = var.aws_region
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  tags = {
    Name = "terraform-web"
  }
}

5-1. ポイント

  • variable "aws_region" で入力変数を定義
  • 参照は var.aws_region
  • var.ami_id のように使う

イメージ

  • variable = 外から渡してもらう入力
  • output = 外へ返す出力

variable は関数でいう「引数」のようなものです。


6. data ブロックとは何か

Terraform でかなり重要なのが data です。

一言でいうと:

  • resource = 作る
  • data = 既にあるものを読む

です。

6-1. resource との違い

resource

resource "aws_instance" "web" {
  ami           = "ami-xxxxxxxx"
  instance_type = "t3.micro"
}

これは EC2 を 新しく作る です。

data

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

これは AWS に既にある AMI を 検索して読む です。

6-2. AWS でよくある使い方

  • 既存の VPC を使う
  • 既存の Subnet を使う
  • 最新の Amazon Linux AMI を使う
  • 既存の Route53 Hosted Zone を使う

6-3. AMI を取得して EC2 を作る例

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

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

  tags = {
    Name = "terraform-web"
  }
}

ここでの

data.aws_ami.amazon_linux.id

は、

  • data
  • aws_ami
  • amazon_linux
  • id

という順で、取得した AMI の ID を参照 しています。


7. locals とは何か

locals は、自分の Terraform 設定の中で使う中間値や共通値をまとめる仕組み です。

7-1. data との違い

  • data = 外から情報を取ってくる
  • locals = 中で使う値を整える

locals の例

locals {
  project_name  = "sample-app"
  env           = "dev"
  instance_name = "${local.project_name}-${local.env}-web"

  common_tags = {
    Project = local.project_name
    Env     = local.env
  }
}

これは外部に問い合わせていません。
単に Terraform 内部で値を作っているだけです。

7-2. datalocals を並べると

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

locals {
  project_name  = "sample-app"
  env           = "dev"
  instance_name = "${local.project_name}-${local.env}-web"
}
  • data.aws_ami.amazon_linux.id は AWS から取ってきた値
  • local.instance_name は自分で組み立てた値

7-3. 判断基準

data を使う

  • AWS に問い合わせる必要がある
  • 既存リソースを探したい
  • provider から値を取得したい

locals を使う

  • 文字列結合したい
  • 共通タグをまとめたい
  • 長い式に名前を付けたい

8. dataresourcelocals を組み合わせる AWS 例

variable "ami_id" {
  type = string
}

locals {
  project_name  = "sample-app"
  env           = "dev"
  instance_name = "${local.project_name}-${local.env}-web"
  common_tags = {
    Project = local.project_name
    Env     = local.env
  }
}

data "aws_subnet" "public_a" {
  filter {
    name   = "tag:Name"
    values = ["public-subnet-a"]
  }
}

resource "aws_security_group" "web_sg" {
  name   = "${local.project_name}-${local.env}-web-sg"
  vpc_id = var.vpc_id

  tags = local.common_tags
}

resource "aws_instance" "web" {
  ami                    = var.ami_id
  instance_type          = "t3.micro"
  subnet_id              = data.aws_subnet.public_a.id
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = merge(local.common_tags, {
    Name = local.instance_name
  })
}

この例の役割はこうです。

  • variable = 外から値を受け取る
  • locals = 中間値や共通値を作る
  • data = 既存の Subnet を読む
  • resource = Security Group と EC2 を作る

9. output とは何か

output は、最後に外へ見せたい値を公開するための仕組み です。

たとえば、EC2 を作ったあとに

  • インスタンスID
  • パブリックIP
  • Security Group ID

などを表示したいことがあります。
そのために output を使います。

9-1. 基本構文

output "名前" {
  value = 出したい値
}

output "instance_id" {
  value = aws_instance.web.id
}

9-2. AWS 実例

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t3.micro"
}

output "instance_id" {
  value = aws_instance.web.id
}

output "public_ip" {
  value = aws_instance.web.public_ip
}

9-3. datalocals も出せる

output "selected_ami_id" {
  value = data.aws_ami.amazon_linux.id
}

output "instance_name" {
  value = local.instance_name
}

9-4. output のイメージ

  • variable = 入力
  • output = 出力
  • locals = 中間値
  • resource = 作る
  • data = 読む

かなり整理しやすくなります。


10. output の実務での用途

よく出力するものは次のような値です。

  • VPC ID
  • Subnet ID
  • Security Group ID
  • EC2 の IP
  • ALB の DNS 名
  • RDS endpoint

output "instance_info" {
  value = {
    id        = aws_instance.web.id
    public_ip = aws_instance.web.public_ip
    type      = aws_instance.web.instance_type
  }
}

リストやマップも出せます。

10-1. sensitive

機密値を扱うときは sensitive = true を付けられます。

output "db_password" {
  value     = var.db_password
  sensitive = true
}

11. ファイル間の参照に import は必要か

基本は 不要です

Terraform は、同じディレクトリ内の .tf ファイルを自動的にまとめて読み込みます。

たとえば:

variables.tf

variable "instance_type" {
  type    = string
  default = "t3.micro"
}

main.tf

resource "aws_instance" "web" {
  ami           = "ami-xxxxxxxxxxxxxxxxx"
  instance_type = var.instance_type
}

このように、別ファイルでもそのまま参照できます。
Python や JavaScript のような import は通常不要です。

11-1. なぜ不要なのか

Terraform から見ると、同じディレクトリ内の .tf全部で1つの設定 だからです。

よくある分け方

  • provider.tf
  • variables.tf
  • locals.tf
  • main.tf
  • outputs.tf

この分割は読み込みのためではなく、見やすさのため です。


12. 別ディレクトリはどうするのか

別ディレクトリは自動参照されません。
その場合は module を使います。

12-1. 例

.
├── main.tf
└── modules
    └── ec2
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

親側の main.tf:

module "ec2" {
  source = "./modules/ec2"

  instance_type = "t3.micro"
}

つまり整理すると:

  • 同じディレクトリ内 → import 不要
  • 別ディレクトリ → module を使う

13. main.tf には何を書くべきか

Terraform には「main.tf に必ずこれを書く」という厳密ルールはありません。
main.tf慣例的な名前 です。

ただ、一般的には main.tfそのディレクトリの中心となる定義 を置くことが多いです。

13-1. よくある役割分担

  • main.tf
    主要な resourcedatamodule
  • variables.tf
    variable
  • locals.tf
    locals
  • outputs.tf
    output
  • provider.tf
    terraformprovider

13-2. main.tf の例

data "aws_subnet" "public_a" {
  filter {
    name   = "tag:Name"
    values = ["public-subnet-a"]
  }
}

resource "aws_security_group" "web_sg" {
  name   = "${local.project_name}-${local.env}-web-sg"
  vpc_id = var.vpc_id

  tags = local.common_tags
}

resource "aws_instance" "web" {
  ami                    = var.ami_id
  instance_type          = var.instance_type
  subnet_id              = data.aws_subnet.public_a.id
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = merge(local.common_tags, {
    Name = local.instance_name
  })
}

つまり main.tf は、その構成の本体 を置く場所として使うのが分かりやすいです。

13-3. 小規模なら全部 main.tf でもよい

学習用や小規模構成なら、全部 main.tf に書いても問題ありません。
ファイル分割はあくまで 可読性のため です。


14. Security Group を含む AWS 実例

ここまでの知識を組み合わせた、少し実務っぽい例です。

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

variable "aws_region" {
  type    = string
  default = "ap-northeast-1"
}

variable "ami_id" {
  type = string
}

provider "aws" {
  region = var.aws_region
}

locals {
  project_name  = "sample-app"
  env           = "dev"
  instance_name = "${local.project_name}-${local.env}-web"
  common_tags = {
    Project = local.project_name
    Env     = local.env
  }
}

data "aws_subnet" "public_a" {
  filter {
    name   = "tag:Name"
    values = ["public-subnet-a"]
  }
}

resource "aws_security_group" "web_sg" {
  name   = "${local.project_name}-${local.env}-web-sg"
  vpc_id = var.vpc_id

  tags = local.common_tags
}

resource "aws_vpc_security_group_ingress_rule" "http" {
  security_group_id = aws_security_group.web_sg.id
  cidr_ipv4         = "0.0.0.0/0"
  from_port         = 80
  ip_protocol       = "tcp"
  to_port           = 80
}

resource "aws_vpc_security_group_ingress_rule" "ssh" {
  security_group_id = aws_security_group.web_sg.id
  cidr_ipv4         = "0.0.0.0/0"
  from_port         = 22
  ip_protocol       = "tcp"
  to_port           = 22
}

resource "aws_vpc_security_group_egress_rule" "all" {
  security_group_id = aws_security_group.web_sg.id
  cidr_ipv4         = "0.0.0.0/0"
  ip_protocol       = "-1"
}

resource "aws_instance" "web" {
  ami                    = var.ami_id
  instance_type          = "t3.micro"
  subnet_id              = data.aws_subnet.public_a.id
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = merge(local.common_tags, {
    Name = local.instance_name
  })
}

output "instance_id" {
  value = aws_instance.web.id
}

output "security_group_id" {
  value = aws_security_group.web_sg.id
}

14-1. この例の読み方

  • provider で AWS を使う
  • variable で外から受け取る値を定義
  • locals で命名規則や共通タグを作る
  • data で既存 Subnet を取得
  • resource で Security Group と EC2 を作る
  • output で結果を表示する

Terraform の全体像がこの1つにかなり詰まっています。


15. data / locals / resource / output の違いを整理

最後に、ここが一番重要なのでまとめます。

variable

外から受け取る入力

variable "instance_type" {
  type    = string
  default = "t3.micro"
}

locals

Terraform 内で使う中間値

locals {
  instance_name = "sample-dev-web"
}

data

既存情報を読む

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
}

resource

新しく作る

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
}

output

最後に外へ出す

output "instance_id" {
  value = aws_instance.web.id
}

16. 初学者向けの覚え方

まずはこれで十分です。

  • resource = 作る
  • data = 読む
  • locals = 中で使う値を整える
  • variable = 外から入れる
  • output = 外へ出す

そして AWS の場合は、最初は次の形だけ読めれば大丈夫です。

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

resource "aws_XXX" "name" {
  ...
}

そこに少しずつ

  • variable
  • locals
  • data
  • output

を足していけば理解しやすいです。


17. よくあるつまずきポイント

17-1. name とラベルは違う

resource "aws_security_group" "web_sg" {
  name = "terraform-web-sg"
}

ここで:

  • web_sg = Terraform 内の識別名
  • name = "terraform-web-sg" = AWS 上のリソース名

これは別物です。

17-2. ファイル分割しても import は不要

同じディレクトリ内なら .tf は自動的にまとめて読まれます。

17-3. main.tf は特別なファイルではない

ただの慣例です。
aaa.tf でも動きます。

17-4. locals は外から入力できない

入力は variable、内部の中間値は locals です。

17-5. data では作れない

data は既存情報の取得専用です。
新規作成は resource を使います。


18. まとめ

Terraform は最初は記法が独特に見えますが、実際は役割を分けて考えるとかなり整理しやすいです。

  • variable で入力を受ける
  • locals で中間値を作る
  • data で既存情報を読む
  • resource で新規作成する
  • output で結果を出す

さらに、

  • 同じディレクトリ内の .tf は自動的にまとめて読み込まれる
  • main.tf は慣例的に中心のリソースを書くことが多い
  • 別ディレクトリを使うときは module を使う

という流れを押さえると、Terraform の構造がかなり見えてきます。

Terraform 初学者は、まずは次の順で試すのがおすすめです。

  1. local_file で基本構文に慣れる
  2. aws_instance で AWS リソースを1つ作る
  3. variableoutput を追加する
  4. data で既存 AMI や Subnet を読む
  5. locals で命名やタグを整理する
  6. ファイル分割と module を覚える

ここまで理解できると、Terraform を「なんとなく読む」段階から、かなり「自分で書ける」段階に近づきます。


6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?