TerraformのHCLリソース命名規則とタグ戦略|環境・サービス・コスト管理を支える一貫した設計パターン

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Terraform > TerraformのHCLリソース命名規則とタグ戦略|環境・サービス・コスト管理を支える一貫した設計パターン
「プロジェクトのTerraformコードをレビューしたら、リソース名の付け方が人によってバラバラで、どれが本番用か検証用かすら判別できなかった」
そんな状況を経験したことはないだろうか。

Terraformでインフラをコード管理する最大のメリットは再現性と追跡可能性だ。しかし命名規則とタグ戦略が統一されていないと、「このEC2は本番か?」「先月の費用増加はどのサービスが原因か?」をAWSコンソールで瞬時に判断できなくなる。後から命名を直そうとすると terraform state mv を多用する危険なリファクタリングが必要になり、本番障害のリスクを伴う。

この記事では、Terraform 1.7以降 / AWS provider 5.x を前提に、HCLリソースの命名規則とAWSタグ設計のベストプラクティスを実装例つきで解説する。チームで長期運用できる設計パターンを、環境分離・コスト管理・障害対応の3軸で整理する。

この記事のポイント

・HCLブロックラベルとNameタグは役割が異なり、それぞれに命名規則が必要
・localsブロックで共通タグを一元管理すると、全リソースへの変更が1か所で完結する
・環境・サービス・コスト配分の3タグをデフォルト基本セットとして設計する
・命名が崩れるのは「env変数の渡し忘れ」と「コンソール手動上書き」が主な原因


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜTerraformで命名規則とタグを統一するのか

インフラ運用で命名規則が重要な理由は3つある。

障害対応速度
深夜のアラートで「i-0a1b2c3d4e5f」と表示されても、それが本番のWebサーバーか検証環境のバッチかを判断する時間が無駄になる。Nameタグに prod-lm-web-01 と付いていれば即断できる。

コスト管理
AWSのコスト配分タグ(Cost Allocation Tags)を使うと、サービスごと・環境ごとの費用をBilling Dashboardで可視化できる。タグが統一されていなければ、この機能が使えない。

Terraformのstate整合性
HCLのリソースブロックラベル(resource "aws_instance" "web" の web 部分)はTerraformが内部的にstateと紐付けるキーになる。ここが変わると既存リソースの削除→再作成が走る。最初から一貫したルールを設けることで、リファクタリング時の事故を防げる。

Terraformを使ったAWSインフラ管理の体系的な学習については terraform.linuxmaster.jp でも詳しく解説している。

HCLリソース名とAWS Nameタグの設計方針

混乱の原因として多いのが「HCLブロックラベル」と「AWSのNameタグ」を同じものと思い込んでいるケースだ。この2つは役割が異なる。

項目 HCLブロックラベル AWSリソース Nameタグ
用途 Terraform内部でstateを識別する AWSコンソール・CLIで表示される人間向けの名前
変更コスト 高(再作成トリガー) 低(タグ変更だけで済む)
命名ルール 短く・role中心(web / db / bastion) 長く・環境+サービス+連番(prod-lm-web-01)

1. HCLブロックラベルの命名規則

HCLブロックラベルはTerraform内部のアドレスになるため、変更コストが高い。以下の方針を推奨する。

・役割(role)中心の短い名前を使う
・環境名は含めない(環境はworkspaceや変数で切り替える)
・複数台ある場合はfor_eachのキーで表現し、連番は避ける

# NG: 環境名を入れると環境ごとにリソースブロックが増殖する resource "aws_instance" "prod_web_01" { ... } resource "aws_instance" "stg_web_01" { ... } # OK: 役割中心・環境は変数で切り替える resource "aws_instance" "web" { ami = var.ami_id instance_type = var.instance_type tags = local.common_tags }

2. AWSリソース Nameタグの命名規則

Nameタグはタグ変更だけで済むため変更コストが低い。以下の形式を推奨する。

# 形式: {env}-{project}-{role}-{index} # 例 prod-lm-web-01 # 本番 / linuxmaster / Webサーバー / 1台目 stg-lm-web-01 # ステージング / linuxmaster / Webサーバー / 1台目 prod-lm-db-primary # 本番 / linuxmaster / DBサーバー / プライマリ

この形式をlocalsで生成すると、変数変更だけで全環境に伝播できる。

localsブロックで共通タグを一元管理する

Terraformで全リソースに同じタグセットを付けるもっとも効率的な方法は、localsブロックに共通タグマップを定義することだ。

# variables.tf variable "env" { description = "デプロイ環境(dev / stg / prod)" type = string validation { condition = contains(["dev", "stg", "prod"], var.env) error_message = "envはdev / stg / prodのいずれかを指定してください。" } } variable "project" { description = "プロジェクト識別子" type = string default = "lm" } variable "cost_center" { description = "コスト配分タグ(AWSコスト配分タグ設定と一致させる)" type = string }

# locals.tf locals { # 全リソースに付与する共通タグ common_tags = { env = var.env project = var.project managed_by = "terraform" cost_center = var.cost_center } # Nameタグ付きのリソース別タグを生成するヘルパー # merge(local.common_tags, { Name = "..." }) を各リソースで呼ぶ name_prefix = "${var.env}-${var.project}" }

3. 共通タグをリソースに適用する

# main.tf resource "aws_instance" "web" { ami = data.aws_ami.amazon_linux.id instance_type = var.instance_type subnet_id = aws_subnet.public.id tags = merge(local.common_tags, { Name = "${local.name_prefix}-web-01" role = "web" }) } resource "aws_db_instance" "main" { identifier = "${local.name_prefix}-db" engine = "mysql" instance_class = var.db_instance_class allocated_storage = 20 tags = merge(local.common_tags, { Name = "${local.name_prefix}-db-primary" role = "database" }) }

merge()を使うことで、共通タグにリソース固有のタグ(NameやRole)を追加できる。全リソースに同じ local.common_tags を使うため、var.env を1か所変えるだけで全リソースのタグが更新される。

環境・サービス・コスト配分に対応したタグ設計

AWSのコスト管理に直結する3種のタグを、設計の基本セットとして定義する。

タグキー 値の例 用途
env dev / stg / prod 環境分離・リソース識別
project lm / store / admin プロジェクト・サービス識別
cost_center backend-01 / frontend-02 AWSコスト配分タグと一致させる
managed_by terraform 手動作成リソースとの区別(固定値)
Name prod-lm-web-01 AWSコンソールでの表示名(リソースごとに付与)

4. コスト配分タグをAWSに有効化する手順

localsでタグを統一しても、AWSのコスト配分タグ機能を有効化しないとBilling Dashboardで集計できない。以下の手順を実施する。

・AWSコンソール → Billing → Cost Allocation Tags を開く
・「User-defined cost allocation tags」の一覧から対象タグを確認する
・Terraformで付与した project / cost_center / env を「アクティブ化」する
・24時間後からBilling Dashboardでフィルタリングが有効になる

この設定はTerraformリソース(aws_ce_cost_allocation_tag)でも管理できる。

# cost_allocation.tf resource "aws_ce_cost_allocation_tag" "env" { tag_key = "env" status = "Active" } resource "aws_ce_cost_allocation_tag" "project" { tag_key = "project" status = "Active" } resource "aws_ce_cost_allocation_tag" "cost_center" { tag_key = "cost_center" status = "Active" }

for_eachとmergeでリソースごとのタグ差分を吸収する

同じ種類のリソースを複数台デプロイする場合、for_eachとタグのmergeを組み合わせると重複コードを大幅に削減できる。

# variables.tf variable "web_servers" { description = "Webサーバーのマップ(キーがNameタグの一部になる)" type = map(object({ instance_type = string subnet_id = string extra_tags = map(string) })) default = {} }

# terraform.tfvars(dev環境) web_servers = { "web-01" = { instance_type = "t3.micro" subnet_id = "subnet-aabbcc11" extra_tags = { az = "ap-northeast-1a" } } "web-02" = { instance_type = "t3.micro" subnet_id = "subnet-ddeeff22" extra_tags = { az = "ap-northeast-1c" } } }

# main.tf resource "aws_instance" "web" { for_each = var.web_servers ami = data.aws_ami.amazon_linux.id instance_type = each.value.instance_type subnet_id = each.value.subnet_id tags = merge( local.common_tags, { Name = "${local.name_prefix}-${each.key}" role = "web" }, each.value.extra_tags # AZなどリソース固有のタグ ) }

merge()の優先順位は「後の引数が勝つ」。共通タグ → 役割タグ → リソース固有タグの順で上書きが起きる。extra_tagsで共通タグを意図せず上書きしてしまわないよう、extra_tagsに env や managed_by を入れないことをチーム規約として設定しておく。

デプロイ後にタグを確認すると、各リソースに意図したタグが付いていることを実機で検証できる。

$ aws ec2 describe-instances \ --filters "Name=tag:env,Values=dev" \ --query 'Reservations[].Instances[] .{ID:InstanceId, Name:Tags[?Key==`Name`].Value|[0], Env:Tags[?Key==`env`].Value|[0], Cost:Tags[?Key==`cost_center`].Value|[0]}' \ --output table -------------------------------------------------------------------- | DescribeInstances | +----------------------+----------+--------------+-----------------+ | Cost | Env | ID | Name | +----------------------+----------+--------------+-----------------+ | backend-01 | dev | i-0a1b2c3d4e | dev-lm-web-01 | | backend-01 | dev | i-0b2c3d4e5f | dev-lm-web-02 | +----------------------+----------+--------------+-----------------+

命名・タグ設計の典型的な失敗パターンと対処手順

5. 失敗パターン1: env変数を渡し忘れてデフォルト値のまま適用される

var.env にデフォルト値を設定していると、-var env=prodを渡し忘れても適用できてしまう。本番に env=dev タグが付いたリソースが生まれる。

# NG: デフォルト値があると渡し忘れを検出できない variable "env" { type = string default = "dev" # ← 渡し忘れても通ってしまう } # OK: デフォルト値を設定せず、validationで許容値を明示する variable "env" { type = string validation { condition = contains(["dev", "stg", "prod"], var.env) error_message = "envはdev / stg / prodのいずれかを指定してください。" } }

validationブロックで許容値を明示することで、誤った値の入力も防げる。

6. 失敗パターン2: コンソールで手動タグ上書きしてterraform planに差分が出続ける

AWSコンソールでタグを手動変更すると、次の terraform plan で差分が検出される。

# aws_instance.web will be updated in-place ~ resource "aws_instance" "web" { ~ tags = { ~ "cost_center" = "backend-02" -> "backend-01" # (3 unchanged elements hidden) } } Plan: 0 to add, 1 to change, 0 to destroy.

手動変更が正しい内容の場合は terraform.tfvars を修正してapplyする。手動変更を一切禁止したい場合は、lifecycle { ignore_changes = [tags] } を使わず「コンソール手動変更禁止」をチーム規約として徹底する方が、stateの整合性を保てる。

7. 失敗パターン3: HCLブロックラベルを後から変更してリソースが再作成される

# 変更前 resource "aws_instance" "web_server" { ... } # stateキー: aws_instance.web_server # 変更後(命名を直した) resource "aws_instance" "web" { ... } # stateキー: aws_instance.web

この変更をそのまま terraform apply すると「aws_instance.web_server削除 + aws_instance.web新規作成」が実行される。本番EC2の停止・再起動が発生する。

Terraform 1.1以降なら movedブロックでstateのキーを変更できる。

# moved.tf(一時的に追加し、apply後に削除する) moved { from = aws_instance.web_server to = aws_instance.web }

movedブロックを使うと、リソースを破壊せずstateのアドレスだけを変更できる。適用後は moved.tf を削除し、次の terraform plan で差分がゼロになることを確認する。

本記事のまとめ

設計項目 推奨方針
HCLブロックラベル 役割中心の短い名前(web / db / bastion)。環境名は含めない
AWSリソース Nameタグ {env}-{project}-{role}-{index}形式。localsで生成する
共通タグの管理 locals.common_tagsに定義。全リソースはmerge()で適用する
基本タグセット env / project / cost_center / managed_by / Name の5つ
リソース固有タグ merge()の最後の引数で追加。共通タグを上書きしない設計にする
var.envのバリデーション デフォルト値を設定せず、validationブロックで許容値を明示する
ブロックラベル変更 movedブロックで対応。直接変更は削除→再作成トリガーになる
命名規則とタグ設計はTerraformの「インフラ設計」の入口だ。コードを書き始める前に設計方針を決め、locals.tf と variables.tf を先にコミットすることを推奨する。後から直すコストは、最初に設計するコストの何倍にもなる。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、TerraformによるLinuxインフラのコード管理を基礎から体系的に学べる講座を用意しています。HCL設計・state管理・CI/CDパイプライン構築まで、現役エンジニアが実務で使う手順をハンズオン形式で習得できます。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。