Terraformを始めたいのに、認証でつまずき、ステートが怖く、planの差分が消えない。
AWS/Azure/GCPのどこから着手し、モジュール化やCI/CD、セキュリティはどう整えるのか——本記事が一気に解決します。
最小構成からバージョン固定、リモートステート、無停止更新、ポリシー運用まで、現場で効くTerraform実践を具体例で紹介します。
この記事は以下のような人におすすめ!
- Terraformとは何か知りたい人
- AWS/Azure/GCPそれぞれでTerraformの認証をどう通すかが分からない
- どの環境変数を設定すべきかわからない
Terraformとは何か
クラウドやサーバを手作業でクリックして作るのではなく、コードでインフラを設計・構築・変更する考え方を実現するのが「Terraform」です。
Terraformは宣言的な記法と豊富なプロバイダを備え、AWSやAzure、Google Cloud、さらにはSaaSまで横断的に扱えます。
つまり、同じワークフローでマルチクラウドを一貫管理できるため、規模が大きくなるほど運用コストを下げ、変更の安全性を高めます。
さらに、TerraformのコードはGitでバージョン管理できるので、レビューや再現性の確保が容易です。
したがって、Terraformは初学者のスモールスタートから、企業の大規模運用まで幅広く適合します。
1-1. Terraformの基本概念と特徴(宣言的・IaC・マルチクラウド)
1-1-1. 宣言的に「あるべき姿」を書くとは
Terraformでは「最終的に存在してほしいインフラの状態(あるべき姿)」をコードで宣言します。なぜなら、手順(手続き)ではなく結果を記述することで、差分計算と自動適用が機械的に行えるからです。
たとえば、「このリージョンにVPCを1つ、サブネットを2つ、タグはこう」と記述すれば、Terraformが現在のクラウドと照合して不足分や不要分を検出します。
その結果、変更点だけが適用され、冪等性(同じ操作を繰り返しても同じ結果になる性質)を担保できます。
1-1-2. Infrastructure as Codeとしてのメリット
Infrastructure as Code(IaC)としてTerraformを採用するメリットは次のとおりです。
- 変更の見える化:
terraform plan
で差分を事前に確認可能。レビュー文化と相性が良い。 - 再現性とドリフト対策:コードが唯一の設計書となり、手作業との差異(ドリフト)を早期に発見。
- 自動化とスピード:CI/CDに組み込むことで、申請から構築までの時間を短縮。
- 監査容易性:履歴(誰が、いつ、何を変えたか)がGitに残る。
1-1-3. マルチクラウド対応とプロバイダの仕組み
Terraformは「プロバイダ」と呼ばれるプラグインを介して各サービスと対話します。
したがって、AWS・Azure・Google Cloudはもちろん、Kubernetesや各種SaaSまで同じHCL(HashiCorp Configuration Language)で記述可能です。
さらに、複数プロバイダを同一リポジトリで扱えるため、たとえば「AWS上のVPCと、SaaSのモニタリング設定を同時に管理する」といった現実的なユースケースに強いのが特徴です。
1-2. 競合ツールとの違い(CloudFormation/Bicep/Pulumiの比較観点)
1-2-1. 言語・記法の違い(HCL/DSL/汎用言語)
- Terraform:HCLという宣言的記法。学習しやすく、読みやすさ重視。
- CloudFormation:JSON/YAML中心。AWSに深く最適化。
- Bicep:Azure専用の宣言的DSL。ARMテンプレートを簡潔に記述。
- Pulumi:TypeScript/Python/Go/C#など汎用言語でIaCを実装。ロジック表現が柔軟。
1-2-2. 対応範囲とロックインの度合い
- Terraform:マルチクラウド+SaaSまで広くカバー。ベンダーロックインを最小化。
- CloudFormation:AWSに最適化。サービス追随の速さが強み。
- Bicep:Azure特化。Azureの最新機能を活用しやすい。
- Pulumi:複数クラウド対応だが、言語ランタイム依存が発生。
1-2-3. 学習コスト・チーム適合・運用性
- 学習コスト:HCL(Terraform)は読み書きが素直。Bicepも簡潔。Pulumiは言語依存のため開発者フレンドリー。
- 運用性:Terraformは
plan
中心のレビュー文化と相性が良く、モジュールやレジストリが豊富。 - チーム適合:アプリ開発者メインならPulumi、クラウド専任チームやSRE中心ならTerraform/Bicep/CloudFormationがフィットしやすい。
主要視点での比較表
観点 | Terraform | CloudFormation | Bicep | Pulumi |
---|---|---|---|---|
記法/言語 | HCL(宣言的) | JSON/YAML(宣言的) | Bicep DSL(宣言的) | 汎用言語(TypeScript 等) |
対応範囲 | マルチクラウド+SaaS | AWS専用 | Azure専用 | マルチクラウド |
学習しやすさ | 高い(読みやすい) | 中(YAML慣れが必要) | 高い(簡潔) | 言語に依存 |
エコシステム | モジュール豊富 | AWS機能追随に強い | Azure連携に強い | ランタイムの柔軟性 |
ロックイン | 低め | 高い(AWS) | 高い(Azure) | 中(言語ランタイム) |
向く場面 | 組織横断・統一運用 | AWS特化運用 | Azure特化運用 | アプリ開発者主導 |
つまり、クラウド横断の標準ワークフローを整えたい組織にはTerraformが強く、単一クラウドに深く最適化したい場合はベンダー純正ツールが選択肢になります。
1-3. 基本ワークフローの全体像(init・plan・apply・destroyの流れ)
Terraformの価値は、シンプルで再現性の高いワークフローにあります。
なぜなら、どのクラウドであっても以下の手順が共通で、変更の可視化と安全な適用を常に実現できるからです。
1-3-1. init:プロジェクトの初期化とプロバイダ取得
初回やプロバイダ変更時に実行します。必要なプラグインやバックエンド設定を取得し、作業ディレクトリを初期化します。
terraform init
ポイント
- プロバイダのバージョン固定で再現性を確保。
- リモートステート(後述のバックエンド)を使う場合は、この段階で設定。
- したがって、
init
の成功がその後のplan/apply
の安定性を左右します。
1-3-2. plan:差分の可視化とレビュー
plan
は現在のクラウドとコードを比較し、追加・変更・削除の差分を示します。つまり、実行前に「何が起きるか」を確認でき、レビューや承認プロセスに組み込みやすいのが強みです。
terraform plan -out=tfplan
ポイント
- 差分の可視化により、破壊的変更の事前検知が可能。
-out
で保存すれば、レビュー後に同一プランをapply
できる。- その結果、ヒューマンエラーの多くをレビュー段階で抑止できます。
1-3-3. apply/destroy:適用と破棄の安全運転
レビュー済みのプランを適用して変更を実行します。逆に、環境を撤去したいときはdestroy
を使います。
terraform apply tfplan
terraform destroy
安全運用のコツ
- 小さな単位で頻繁に適用する(大規模変更を避ける)。
- タグや命名規約を統一し、意図しない削除を回避。
- ワークスペースや環境(dev/stg/prod)を分け、影響範囲を限定。
したがって、Terraformのワークフローは「初期化 → 差分の可視化 → 安全な適用 → 必要なら撤去」という明快な循環でできており、学習直後からチーム運用までスケールします。
はじめてのTerraform環境構築
はじめてTerraformを触る読者が、最短で「動いた」を体験し、かつ実務に耐える基礎を固められるように、インストールから最小サンプル、ファイル構成までを一気通貫で解説します。
つまり、この章を読み終えるころには、TerraformのCLI操作に迷わず、HCLの基本が自然に身についた状態になります。
2-1. インストールと初期設定(CLI・認証・ディレクトリ構成)
2-1-1. CLIのインストール(macOS/Windows/Linux)
まずはTerraform CLIを導入します。
なぜなら、CLIがTerraformの中核であり、init / plan / apply / destroy
の全操作を担うからです。
代表的な導入方法は次のとおりです。
OS | 代表的な方法 | 例コマンド |
---|---|---|
macOS | Homebrew | brew tap hashicorp/tap brew install hashicorp/tap/terraform |
Windows | winget または Chocolatey | winget install HashiCorp.Terraform choco install terraform |
Linux (Deb系) | APT | sudo apt-get update && sudo apt-get install -y terraform |
Linux (RHEL系) | DNF/YUM | sudo dnf install -y terraform または sudo yum install -y terraform |
導入後は次で確認します。
terraform -version
バージョンを固定したい場合は後述のrequired_version
を使います。
したがって、チーム運用ではまずバージョンの再現性を確保しましょう。
2-1-2. 認証の準備(AWS/Azure/Google Cloud)
Terraformはプロバイダ経由で各クラウドへ接続します。つまり、認証情報を正しく設定できれば、Terraformは安全にリソースを作成できます。
代表例は次のとおりです。
- AWS
- 環境変数:
AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
、必要に応じてAWS_SESSION_TOKEN
- プロファイル:
~/.aws/credentials
にプロファイルを定義し、AWS_PROFILE
で切り替え
- 環境変数:
- Azure
- Azure CLIでサインイン:
az login
- サービスプリンシパルを用いたクライアントID/シークレット連携
- Azure CLIでサインイン:
- Google Cloud
gcloud auth application-default login
でアプリケーション既定認証を設定- サービスアカウント鍵JSONを
GOOGLE_APPLICATION_CREDENTIALS
で指す
ポイント
- 認証情報をHCLに直書きしない(環境変数や資格情報ストアを利用)。
- 原則として最小権限の付与にとどめる。
- 検証後は不要な資格情報を速やかに無効化する。
2-1-3. 推奨ディレクトリ構成(最初はシンプルに)
最初はシンプルに始め、のちに拡張できる形が扱いやすいです。
infra/
versions.tf # Terraform本体/プロバイダのバージョン宣言
providers.tf # provider “aws” 等の設定
main.tf # リソース定義の本体
variables.tf # 変数の宣言(型・デフォルト)
outputs.tf # 出力値(ID 等)
terraform.tfvars # 変数の実値(Git管理は慎重に)
将来的にmodules/
ディレクトリを追加し、共通化したい単位を切り出すと、Terraformの再利用性が一気に高まります。
だからこそ、早い段階でファイルの役割分担を意識しておくと後が楽になります。
2-2. 最小構成のサンプルを動かす(プロバイダ設定と最初のリソース)
2-2-1. 最短ルート:クラウド認証なしで動くlocal
プロバイダ
まずは成功体験を得るために、ローカルファイルを作るだけのlocal
プロバイダでTerraformを動かします。
つまり、クラウドの認証が不要なので、環境差に左右されません。
versions.tf
terraform {
required_version = “>= 1.6.0”
required_providers {
local = {
source = “hashicorp/local”
version = “~> 2.4”
}
}
}
main.tf
resource “local_file” “hello” {
filename = “${path.module}/hello.txt”
content = “Hello Terraform”
}
実行手順
terraform init
terraform plan
terraform apply -auto-approve
結果として、カレントディレクトリにhello.txt
が作成されます。
片付けは次で完了します。
terraform destroy -auto-approve
2-2-2. AWSの例:S3バケットを1つ作る
次に、実際のクラウドに対して最小リソースを作る例です。なぜなら、Terraformの真価はクラウドリソースの宣言的管理にあるからです。
ここではS3バケットを例にします(ユニークな名前が必要です)。
providers.tf
terraform {
required_providers {
aws = {
source = “hashicorp/aws”
version = “~> 5.0”
}
}
}
provider “aws” {
region = var.aws_region
}
variables.tf
variable “aws_region” {
type = string
description = “AWS region, e.g. ap-northeast-1”
default = “ap-northeast-1”
}
variable “bucket_name” {
type = string
description = “Unique S3 bucket name”
}
main.tf
resource “aws_s3_bucket” “this” {
bucket = var.bucket_name
tags = {
Project = “terraform-getting-started”
Env = “dev”
}
}
outputs.tf
output “bucket_name” {
value = aws_s3_bucket.this.bucket
}
terraform.tfvars
(例)
bucket_name = “your-unique-bucket-name-12345”
実行
terraform init
terraform plan
terraform apply
注意点
- バケット名は世界で一意にする必要があります。
- 検証後は
terraform destroy
で削除し、コストと不要資源の放置を避けます。 - 認証は2-1-2の手順を満たしている前提です。
2-2-3. つまずき回避のコツ(ドリフトと命名)
- 小さい変更を高頻度で適用する(大規模変更を避ける)。
- タグと命名規約を最初に決める。だからこそ、後の検索性と棚卸しが楽になります。
- 手作業変更(ドリフト)は極力避ける。どうしても必要なら、直後に
terraform import
やterraform state
で整合を取る。
2-3. Terraformのファイル構成と書き方(HCL・main/variables/outputs)
2-3-1. 役割で分けると読みやすくなる
ファイル | 役割 | 代表的な中身 |
---|---|---|
versions.tf | バージョン固定 | required_version 、required_providers |
providers.tf | 認証・接続 | provider "aws" など |
main.tf | 中心ロジック | resource 、data 、module |
variables.tf | 変数宣言 | variable "xxx" { type = string } |
outputs.tf | 出力 | output "id" { value = ... } |
terraform.tfvars | 変数の実値 | 環境ごとの値を定義 |
.terraform.lock.hcl | 依存ロック | プロバイダ版数の固定(自動生成) |
この分割により、レビューしやすく、Terraformの変更範囲がひと目で分かります。したがって、チーム運用での衝突や見落としが減ります。
2-3-2. HCLの基本文法(ブロック/引数/式)
HCLは読みやすさを重視した宣言的言語です。
# ブロックの例
resource “aws_instance” “web” {
ami = var.ami
instance_type = “t3.micro”
tags = {
Name = “web”
}
}
# 参照の例(HCL2)
output “instance_id” {
value = aws_instance.web.id
}
基本ルール
- ブロックは「種類」「タイプ」「名前」で表現(例:
resource "aws_instance" "web"
)。 - 参照はドット記法でシンプル(
${}
は原則不要)。 - マップやリスト、for式なども利用可能。だから、冗長になりやすい設定も簡潔に表現できます。
2-3-3. 変数と出力の最小例
variables.tf
variable “project” {
type = string
description = “Project tag”
default = “demo”
}
main.tf
locals {
common_tags = {
Project = var.project
Owner = “platform-team”
}
}
resource “aws_s3_bucket” “this” {
bucket = “${var.project}-bucket-example-12345”
tags = local.common_tags
}
outputs.tf
output “tags” {
value = local.common_tags
}
このように、variable
→local
→resource
→output
という流れが分かると、Terraformの読み書きが一気に楽になります。
2-3-4. バージョン固定とバックエンドの宣言
最後に、再現性とチーム運用の要です。
versions.tf
terraform {
required_version = “~> 1.9.0”
required_providers {
aws = {
source = “hashicorp/aws”
version = “~> 5.0”
}
}
}
providers.tf
(例:S3をバックエンドにする)
terraform {
backend “s3” {
bucket = “your-tfstate-bucket”
key = “env/dev/terraform.tfstate”
region = “ap-northeast-1”
# encrypt = true 等も検討
}
}
- バックエンドはTerraformの状態ファイル(tfstate)を保管します。
- リモートステートにするとロックと共有が可能になり、したがってチームでの同時編集事故を防げます。
- 機密性が必要な場合は、サーバ側暗号化やKMS連携を必ず検討してください。
実務で必須の基礎知識
Terraformを実務で安全かつ効率よく使うには、「プロバイダ」「ステート」「モジュール」「変数・出力・データソース」「ライフサイクル」の五つを押さえることが近道です。
つまり、ここを理解すれば、Terraformの保守性と再現性が一気に向上します。
3-1. プロバイダとリソースの理解(バージョン固定・認証方式)
3-1-1. バージョン固定は再現性の土台
Terraformでは、Terraform本体と各プロバイダのバージョンを固定しておくと、環境差による事故を防げます。
したがって、required_version
とrequired_providers
を必ず宣言します。
terraform {
required_version = “~> 1.9.0”
required_providers {
aws = { source = “hashicorp/aws”, version = “~> 5.0” }
}
}
ポイント
- チームで同一バージョンを使うことで、
plan
の差分が安定します。 .terraform.lock.hcl
はプロバイダ依存のロックファイル。Gitで共有すると再現性がさらに高まります。
3-1-2. 認証方式の基本原則(クラウド共通)
Terraformの認証は「HCLに秘密を書かない」が原則です。なぜなら、コードの共有・レビューが難しくなるからです。共通パターンは次のとおりです。
- 環境変数やCLIログインで認証(例:
AWS_PROFILE
、az login
、gcloud auth
)。 - サービスアカウント/ロールなど、権限は最小限に。
- 機密はシークレットマネージャやCIのシークレット機能で注入。
3-1-3. リソースとデータソースの違い
- resource:実体を作成・変更・削除する(例:VPC、VM、S3バケット)。
- data:既存情報を読み取るだけ(例:最新AMIのID、既存VPCの参照)。
data “aws_ami” “al2023” {
most_recent = true
owners = [“amazon”]
filter { name = “name”, values = [“al2023-ami-*”] }
}
resource “aws_instance” “web” {
ami = data.aws_ami.al2023.id
instance_type = “t3.micro”
}
3-1-4. 複数プロバイダ/エイリアスの活用
アカウントやリージョンをまたぐ場合はalias
を使います。
つまり、同一リポジトリで多環境を安全に扱えます。
provider “aws” {
region = “ap-northeast-1”
}
provider “aws” {
alias = “us”
region = “us-east-1”
}
resource “aws_s3_bucket” “jp” { bucket = “example-jp” }
resource “aws_s3_bucket” “us” {
provider = aws.us
bucket = “example-us”
}
3-2. ステート管理の基礎(ローカルとリモート、バックエンドの選択)
3-2-1. tfstateとは何か
terraform.tfstate
は「実際のインフラのスナップショット」です。Terraformはこのステートをもとに差分を計算します。
だからこそ、破損・衝突・漏えいを絶対に避ける必要があります。
3-2-2. ローカル vs リモートの比較
項目 | ローカルステート | リモートステート |
---|---|---|
共有 | しづらい | しやすい(URLで共有) |
ロック | なし | あり(DynamoDB 等で実現) |
セキュリティ | 端末依存 | サーバ側暗号化・権限管理可 |
向く場面 | 個人検証 | チーム運用・本番 |
したがって、実務では基本的にリモートステートを選びます。
3-2-3. 代表的バックエンドの選択肢
- S3 + DynamoDBロック(AWS)
- GCS(GCP)
- azurerm(Azure Storage)
- remote(Terraform Cloud/Enterprise)
例:S3バックエンド
terraform {
backend “s3” {
bucket = “tfstate-bucket”
key = “env/prod/terraform.tfstate”
region = “ap-northeast-1”
dynamodb_table = “tfstate-lock”
encrypt = true
}
}
3-2-4. ロックと並行実行
同時apply
は競合の温床です。だから、ロック機構を必ず有効化しましょう。
S3ならDynamoDBロック、GCSやazurermでもネイティブのロック機能を活用します。
3-2-5. ドリフト検知とステート操作の最小化
手作業変更はドリフト(実際とステートの乖離)を生みます。検知にはterraform plan
が有効です。
また、ステート直接編集は最後の手段です。必要なら以下で慎重に扱います。
terraform import
:既存リソースを取り込みterraform state mv/rm
:参照の移動や除外terraform plan -refresh-only
:読み取りのみ更新
3-2-6. ワークスペースの考え方
dev
/stg
/prod
の分離にはワークスペースかディレクトリ分割を使います。小規模はワークスペースで十分。
ただし、強い隔離や異なるバックエンドが必要ならディレクトリ/リポジトリ分割が無難です。
3-3. モジュール活用と再利用(公式レジストリ・自作モジュール)
3-3-1. モジュールとは
Terraformモジュールは「入力(variables)と出力(outputs)を持つ再利用可能な部品」です。
つまり、共通VPCや標準監視などを部品化して横展開できます。
module “vpc” {
source = “./modules/vpc”
name = “core”
azs = [“ap-northeast-1a”, “ap-northeast-1c”]
}
3-3-2. 公式レジストリの使いどころ
実績ある公開モジュールで素早く構築できます。
ただし、バージョン固定と入力の最小化を徹底し、ブラックボックス化を避けましょう。
module “vpc” {
source = “terraform-aws-modules/vpc/aws”
version = “~> 5.0”
name = “core”
cidr = “10.0.0.0/16”
}
3-3-3. 自作モジュール設計の原則
- インターフェースは狭く(必要最小限の変数)
- デフォルト値は安全側(タグ・暗号化・最小権限)
- 出力は用途本位(上位が参照しやすいID・ARNを返す)
- **READMEと例(examples/)**で使い方を明示
3-3-4. バージョニングと互換性
モジュールはSemVerで管理し、破壊的変更はメジャーアップ。
したがって、呼び出し側は~>
や明示レンジで安定運用します。
module “web” {
source = “git::ssh://git.example.com/iac/web.git?ref=v2.3.1”
version = “>= 2.3.0, < 3.0.0”
}
3-3-5. テストと品質担保
- 静的検証:
terraform fmt
、terraform validate
、tflint
- 実行テスト:
terratest
や非本番アカウントでのapply
- CI:
plan
の差分をPRに貼り、レビュー駆動で品質を維持
3-3-6. リポジトリ戦略
- モノレポ:横断的な共通化・一括変更に強い
- マルチレポ:境界が明確、変更の影響範囲が読みやすい
組織規模や権限設計に合わせて選択します。
3-4. 変数・出力・データソースの設計(型・デフォルト・参照)
3-4-1. 変数の型・バリデーション・機密
型と検証を定義すると、Terraformの入力品質が安定します。さらに、sensitive
で出力やログへの露出を抑えられます。
variable “instance_type” {
type = string
description = “EC2 instance type”
default = “t3.micro”
validation {
condition = can(regex(“^t3\\.”, var.instance_type))
error_message = “t3系のみ許可します。”
}
}
variable “db_password” {
type = string
sensitive = true
}
3-4-2. デフォルトと値の注入経路
default
で安全側の初期値terraform.tfvars
や-var-file
で環境ごとに上書き- CIでは環境変数/シークレットから渡す
この多段構成により、Terraformの設定は柔軟かつ再現可能になります。
3-4-3. 出力の設計
出力は上位のモジュールやツールが使いやすい形にします。
必要に応じてsensitive = true
を設定。
output “vpc_id” {
value = aws_vpc.main.id
description = “Created VPC ID”
}
3-4-4. データソース活用のコツ
既存リソースや最新値の参照にdata
を使います。さらに、リモートステートの出力を取り込むことで、スタック間連携が簡潔になります。
data “terraform_remote_state” “network” {
backend = “s3”
config = {
bucket = “tfstate-bucket”
key = “env/prod/network.tfstate”
region = “ap-northeast-1”
}
}
resource “aws_instance” “app” {
subnet_id = data.terraform_remote_state.network.outputs.private_subnet_id
}
3-4-5. 参照パターン:locals
と式を賢く使う
locals
で共通値を集約し、try
/coalesce
/条件式で分岐を簡潔に書くと、Terraformの可読性が上がります。
locals {
common_tags = {
Project = var.project
Env = var.env
}
subnet_ids = try(var.custom_subnet_ids, data.terraform_remote_state.network.outputs.default_subnets)
}
3-5. ライフサイクル・依存関係・破壊的変更の扱い
3-5-1. 依存関係の基本:暗黙と明示
Terraformは参照があれば暗黙に依存関係を解決します。参照がないのに順序を保証したい場合のみ、depends_on
を使います。
resource “aws_iam_role” “app” { /* … */ }
resource “aws_iam_role_policy_attachment” “attach” {
role = aws_iam_role.app.name
policy_arn = “arn:aws:iam::aws:policy/ReadOnlyAccess”
depends_on = [aws_iam_role.app] # 参照が無い場合のみ
}
3-5-2. lifecycle
メタ引数の実践
破壊的変更を避けたり、意図しない揮発を防ぐのに有効です。
resource “aws_autoscaling_group” “blue” {
# …
lifecycle {
create_before_destroy = true # 先に新規作成してから古い方を削除(無停止切替)
prevent_destroy = true # うっかり削除を防止
ignore_changes = [tags] # 人手で変わりがちな属性は無視
replace_triggered_by = [aws_launch_template.web] # LT変更時に置換
}
}
さらに、条件チェックには前後条件が便利です。
resource “aws_instance” “web” {
# …
lifecycle {
precondition {
condition = var.instance_type != “t2.micro”
error_message = “生産環境で t2.micro は使用できません。”
}
}
}
3-5-3. 破壊的変更の検出と回避
- 早めに
plan
して差分を可視化 -out
で固定プランを作り、レビュー後に適用-target
は最終手段(依存崩れを招くため恒常運用は避ける)- スキーマ変更時は**
terraform import
**で既存を取り込み、ゼロダウンタイムを設計
3-5-4. moved
ブロックで安全にリファクタ
リソース名変更やモジュール移動時は、moved
で「ここからここへ移動した」と宣言すると、Terraformが破壊と再作成ではなく履歴の移譲として扱います。
moved {
from = aws_s3_bucket.old
to = aws_s3_bucket.main
}
3-5-5. 無停止更新(Blue/Green、create_before_destroy
)
無停止を最優先するなら、Blue/GreenやRollingを検討します。
たとえばASGやLoad Balancerではcreate_before_destroy
と段階的なトラフィック切替を組み合わせると、Terraformで安全な更新が可能です。
その結果、ダウンタイムをほぼゼロにできます。
主要クラウドでの実践手順
Terraformで主要クラウド(AWS・Azure・Google Cloud)を横断的に扱うときの「動く最小構成」を示しつつ、実務でつまずきやすい論点を先回りで解説します。
つまり、ここをなぞれば、Terraformのプロバイダ設定からapply
までを迷わず通過できます。
4-1. AWSでVPCとEC2を作る(プロバイダ設定からapplyまで)
4-1-1. 前提と全体像
- 目的:最小のVPCとサブネット、セキュリティグループ、EC2をTerraformで作成
- 前提:AWS認証は
AWS_PROFILE
または環境変数で設定済み - リージョン例:ap-northeast-1(東京)
4-1-2. プロバイダとバージョン固定
versions.tf
terraform {
required_version = “~> 1.9.0”
required_providers {
aws = { source = “hashicorp/aws”, version = “~> 5.0” }
}
}
providers.tf
provider “aws” {
region = var.aws_region
}
variables.tf
variable “aws_region” { type = string, default = “ap-northeast-1” }
4-1-3. 最小ネットワークとEC2
main.tf
resource “aws_vpc” “main” {
cidr_block = “10.0.0.0/16”
enable_dns_hostnames = true
tags = { Name = “tf-vpc” }
}
resource “aws_subnet” “public_a” {
vpc_id = aws_vpc.main.id
cidr_block = “10.0.1.0/24”
availability_zone = “ap-northeast-1a”
map_public_ip_on_launch = true
tags = { Name = “tf-public-a” }
}
resource “aws_internet_gateway” “igw” {
vpc_id = aws_vpc.main.id
}
resource “aws_route_table” “public” {
vpc_id = aws_vpc.main.id
route { cidr_block = “0.0.0.0/0”, gateway_id = aws_internet_gateway.igw.id }
}
resource “aws_route_table_association” “public_a” {
subnet_id = aws_subnet.public_a.id
route_table_id = aws_route_table.public.id
}
resource “aws_security_group” “web” {
name = “tf-web-sg”
vpc_id = aws_vpc.main.id
ingress { from_port = 22, to_port = 22, protocol = “tcp”, cidr_blocks = [“0.0.0.0/0”] }
egress { from_port = 0, to_port = 0, protocol = “-1”, cidr_blocks = [“0.0.0.0/0”] }
}
data “aws_ami” “al2023” {
most_recent = true
owners = [“amazon”]
filter { name = “name”, values = [“al2023-ami-*”] }
}
resource “aws_instance” “web” {
ami = data.aws_ami.al2023.id
instance_type = “t3.micro”
subnet_id = aws_subnet.public_a.id
vpc_security_group_ids = [aws_security_group.web.id]
associate_public_ip_address = true
tags = { Name = “tf-ec2” }
}
outputs.tf
output “public_ip” { value = aws_instance.web.public_ip }
4-1-4. 実行とポイント
terraform init
terraform plan
terraform apply
- まずは
plan
で差分を可視化。 - その後
apply
で作成。不要になったらdestroy
で撤去。 - なお、セキュリティグループの22番は検証用。実務ではCIDRを限定してください。
4-2. Azureで仮想ネットワークとVMを作る(よくある落とし穴)
4-2-1. 前提と落とし穴の全体像
- 目的:リソースグループ、VNet、サブネット、ネットワーク資源、Linux VMを作成
- 前提:
az login
済み、サブスクリプション選択済み - よくある落とし穴
provider "azurerm"
にfeatures {}
を忘れる- リソースグループのロケーションと各リソースのロケーション不一致
- NSGを作っても、サブネットまたはNICに関連付け忘れだと効果が出ない
- Public IPのSKUとLoad BalancerのSKUの不一致
- 名前の制約(英小文字・長さ・ハイフンのみ等)に違反
4-2-2. プロバイダと基本リソース
versions.tf
terraform {
required_version = "~> 1.9.0"
required_providers {
azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
}
}
providers.tf
provider "azurerm" {
features {}
}
main.tf
resource “azurerm_resource_group” “rg” {
name = “tf-rg”
location = “Japan East”
}
resource “azurerm_virtual_network” “vnet” {
name = “tf-vnet”
address_space = [“10.1.0.0/16”]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource “azurerm_subnet” “subnet” {
name = “tf-subnet”
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = [“10.1.1.0/24”]
}
resource “azurerm_network_security_group” “nsg” {
name = “tf-nsg”
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = “ssh”
priority = 100
direction = “Inbound”
access = “Allow”
protocol = “Tcp”
source_port_range = “*”
destination_port_range = “22”
source_address_prefix = “*”
destination_address_prefix = “*”
}
}
resource “azurerm_subnet_network_security_group_association” “assoc” {
subnet_id = azurerm_subnet.subnet.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
resource “azurerm_public_ip” “pip” {
name = “tf-pip”
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = “Dynamic”
sku = “Basic”
}
resource “azurerm_network_interface” “nic” {
name = “tf-nic”
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = “ipcfg”
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = “Dynamic”
public_ip_address_id = azurerm_public_ip.pip.id
}
}
4-2-3. VM作成と注意点
resource “azurerm_linux_virtual_machine” “vm” {
name = “tf-vm”
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
size = “Standard_B1ms”
admin_username = “azureuser”
network_interface_ids = [azurerm_network_interface.nic.id]
admin_ssh_key {
username = “azureuser”
public_key = file(“~/.ssh/id_rsa.pub”)
}
os_disk {
caching = “ReadWrite”
storage_account_type = “Standard_LRS”
}
source_image_reference {
publisher = “Canonical”
offer = “0001-com-ubuntu-server-jammy”
sku = “22_04-lts-gen2”
version = “latest”
}
}
実務ポイント
- まずは
features {}
、つぎにロケーション整合性を確認。 - NSGは関連付けて初めて有効。
- SKUの組み合わせ(Basic/Standard)は事前に統一ポリシーを決めると事故が減ります。
4-3. Google CloudでVPCとCompute Engineを作る(サービスアカウント設定)
4-3-1. 認証と前提
- いずれかの方法でTerraformの認証を有効化
gcloud auth application-default login
(ADC)- もしくはサービスアカウント鍵JSONを
GOOGLE_APPLICATION_CREDENTIALS
で指定
- プロジェクトID・リージョン(例:asia-northeast1)・ゾーン(例:asia-northeast1-a)を用意
4-3-2. プロバイダとネットワーク
versions.tf
terraform {
required_version = “~> 1.9.0”
required_providers {
google = { source = “hashicorp/google”, version = “~> 6.0” }
}
}
providers.tf
provider “google” {
project = var.project
region = var.region
zone = var.zone
}
variables.tf
variable “project” { type = string }
variable “region” { type = string, default = “asia-northeast1” }
variable “zone” { type = string, default = “asia-northeast1-a” }
main.tf
resource “google_compute_network” “vpc” {
name = “tf-vpc”
auto_create_subnetworks = false
}
resource “google_compute_subnetwork” “subnet” {
name = “tf-subnet”
ip_cidr_range = “10.2.1.0/24”
region = var.region
network = google_compute_network.vpc.id
}
resource “google_compute_firewall” “ssh” {
name = “tf-allow-ssh”
network = google_compute_network.vpc.name
allow { protocol = “tcp”, ports = [“22”] }
source_ranges = [“0.0.0.0/0”]
}
4-3-3. Compute Engine(サービスアカウント付与)
resource “google_service_account” “vm” {
account_id = “tf-vm-sa”
display_name = “tf-vm service account”
}
resource “google_compute_instance” “vm” {
name = “tf-vm”
machine_type = “e2-micro”
zone = var.zone
boot_disk { initialize_params { image = “debian-cloud/debian-12” } }
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
access_config {} # 省略しないと外部IPが付与されない
}
service_account {
email = google_service_account.vm.email
scopes = [“https://www.googleapis.com/auth/cloud-platform”]
}
labels = { env = “dev” }
}
実務ポイント
- サービスアカウントに必要最小限のロールのみ付与(プロジェクトIAMで制御)。
- 外部IPが不要なら
access_config
を省略し、IAPや踏み台経由で接続。 - まずは
plan
で権限不足(403)を早期検知。
4-4. DockerやSaaS連携などマルチプロバイダの例
4-4-1. Dockerコンテナのローカル起動(学習用に最適)
TerraformはローカルのDockerも扱えます。
つまり、クラウド認証なしで「成果」が見えるため、学習の即効性が高いです。
versions.tf
terraform {
required_providers {
docker = { source = “kreuzwerker/docker”, version = “~> 3.0” }
}
required_version = “~> 1.9.0”
}
main.tf
provider “docker” {}
resource “docker_image” “nginx” {
name = “nginx:1.25”
keep_locally = true
}
resource “docker_container” “web” {
name = “tf-nginx”
image = docker_image.nginx.image_id
ports { internal = 80, external = 8080 }
}
apply
後、http://localhost:8080
で動作確認(ネットワークポリシーに注意)。- 片付けは
destroy
で完了。したがって検証サイクルが速い。
4-4-2. SaaS連携の最小例(DNSをCloudflareで管理)
「クラウド+SaaS」を同一リポジトリで管理できるのがTerraformの強みです。
terraform {
required_providers {
cloudflare = { source = “cloudflare/cloudflare”, version = “~> 4.0” }
}
}
provider “cloudflare” {
api_token = var.cloudflare_api_token
}
variable “cloudflare_api_token” { type = string, sensitive = true }
variable “zone_id” { type = string }
resource “cloudflare_record” “app” {
zone_id = var.zone_id
name = “app”
value = “203.0.113.10”
type = “A”
proxied = true
ttl = 300
}
- APIトークンはHCLへ直書きせず、環境変数やCIのシークレットで注入。
- クラウド側のロードバランサのPublic IPと連携すれば、エンドツーエンドで自動化できます。
4-4-3. マルチプロバイダ運用のコツ
- すべてのプロバイダでバージョン固定を徹底
- 共有値は
locals
に集約、機密はsensitive
/シークレットストア - 依存関係は暗黙参照で繋ぎ、必要時のみ
depends_on
- ステートはクラウド別や境界ごとに分割し、破壊範囲を局所化
ベストプラクティスとチーム運用
Terraformをチームで長期運用するなら、コードスタイル、ステート管理、モジュール設計、セキュリティ、CI/CD、ガバナンスの六つを揃えることが近道です。
つまり、日々のterraform plan
とapply
を安全かつ再現可能にし、変更コストと障害リスクを同時に下げられます。
5-1. コードスタイルと命名規約(構造化・フォーマット・タグ付け)
5-1-1. ディレクトリとファイルの構造化指針
まず、Terraformの可読性は「役割で分ける」だけで大きく向上します。
したがって、最初から次の分割を徹底します。
environments/
dev/ # 環境ごとのルート(backend設定も分離)
stg/
prod/
modules/
vpc/
app/
shared/
providers.tf
versions.tf
役割分担の基本
versions.tf
:Terraform本体とプロバイダのバージョン固定providers.tf
:プロバイダ設定(環境変数で認証を注入)main.tf
:主要リソースvariables.tf
:入力定義、outputs.tf
:出力定義
5-1-2. フォーマットと静的検査(fmt/validate/tflint)
Terraformの品質は自動整形と静的検査で担保します。
なぜなら、人手の差異をなくし、レビューを「設計」に集中できるからです。
推奨フロー
terraform fmt -recursive
で整形terraform validate
で構文と参照を検証tflint
でベストプラクティスや命名・型の逸脱を検知
5-1-3. 命名規約・タグ付け・ラベル戦略
タグや名前は「検索・棚卸し・課金把握」の生命線です。
だから、キーと順序を固定します。
項目 | 推奨ルール | 例 |
---|---|---|
リソース名 | <system>-<env>-<role>-<seq> | shop-prod-web-01 |
タグ/ラベル | 固定キー集合を必須化 | Project, Env, Owner, CostCenter |
命名文字 | 英小文字・数字・ハイフン中心 | tf-vpc-core |
変数名 | スネークケース | project_name , allowed_cidrs |
ポイント
- まず
locals
で共通タグを一元化 terraform-docs
等で変数・出力を自動ドキュメント化- 命名とタグは「コスト配賦」「責任境界」と直結するため、最初に決める
5-2. リモートステートとロック、ワークスペース運用
5-2-1. リモートステートの選定基準
Terraformのterraform.tfstate
は最重要資産です。
したがって、暗号化・アクセス制御・ロックを満たすバックエンドを選びます。
バックエンド | 強み | 注意点 |
---|---|---|
S3 + DynamoDBロック | 普及・堅牢・細粒度IAM | バケット名やKMS、リージョン設計が必須 |
GCS | 標準でバージョニング | IAM境界を明確化 |
AzureRM(Storage) | RBAC連携が良好 | コンテナ/キー構成を統一 |
Terraform Cloud/Enterprise | ロック・UI・VCS連携 | 組織ポリシー整備が前提 |
5-2-2. ロックと並行実行のポリシー
apply
の並行実行は競合の温床です。
つまり、本番はロック必須、CIは直列化が安全策です。加えて、変更単位をスモールに保ち、Planの寿命を短く運用します。
5-2-3. ワークスペース運用 vs ディレクトリ分割
- ワークスペース:小規模・同一スキーマの環境切替に便利
- ディレクトリ/リポジトリ分割:強い隔離や異なるバックエンドに最適
結論として、影響範囲をまたぐなら分割、同型の環境ならワークスペースが合理的です。
5-3. モジュール設計指針(入出力設計・バージョニング・テスト)
5-3-1. 入力(variables)の設計
モジュールは「少ないほど強い」です。
なぜなら、入力が増えるほど組み合わせ爆発が起きるからです。
設計原則
- 必須と任意を明示(
nullable
/default
) - 型・バリデーションで不正入力を遮断
- セキュアな既定値(暗号化やタグ)を用意
variable “cidr” {
type = string
description = “VPC CIDR”
validation {
condition = can(cidrnetmask(var.cidr))
error_message = “有効なCIDRを指定してください。”
}
}
5-3-2. 出力(outputs)とドキュメント
上位が使うID・ARN・エンドポイントのみを返し、sensitive
は慎重に付与。
さらに、README
とexamples/
で利用像を固定化すると、Terraformモジュールの再現性が高まります。
5-3-3. バージョニングと互換性
SemVerで管理し、破壊的変更はメジャーアップ。呼び出し側は範囲指定で安定化します。
module “vpc” {
source = “terraform-aws-modules/vpc/aws”
version = “~> 5.0”
}
5-3-4. テスト戦略(静的+実行)
- 静的:
terraform fmt
/validate
、tflint
- 実行:
terratest
や一時アカウントでのapply
- CI:PRに
plan
差分を貼り、レビュー駆動で品質維持
その結果、Terraformの変更は「自信を持ってマージできる状態」に近づきます。
5-4. セキュリティ実践(シークレット管理、権限の最小化、状態ファイル保護)
5-4-1. シークレットの取り扱い
TerraformのHCLに秘密を書かない、が鉄則です。したがって、次を徹底します。
- CIのシークレットストアや各クラウドのシークレットマネージャから注入
variable
にsensitive = true
を設定し、出力やログ露出を抑止- 使い捨て資格情報(短命トークン)を優先
5-4-2. 最小権限(Least Privilege)
- 役割ごとの専用ロール(人と機械を分離)
- 本番と検証でアカウント/サブスクリプションを分割
plan
用読み取り権限とapply
用書き込み権限を分ける
5-4-3. tfstateの保護
tfstateにはIDやARNなど機微が含まれます。
だから、暗号化と厳格なIAM/RBACが必須です。あわせて、バージョニングやアクセスログで監査可能性も確保します。
5-4-4. 監査と可観測性
plan
ファイルの保管(短期)- 変更理由のテンプレート化(PRテンプレ)
- 主要値の
output
を可観測基盤へ送出(例:タグやエンドポイント)
5-5. CI/CDへの組み込み(planのレビューと自動適用のガード)
5-5-1. 三段階パイプライン
- Lint/Validate:
fmt
→validate
→tflint
- Plan:
terraform plan -out=tfplan
をPRに添付 - Apply:本番は手動承認後に
terraform apply tfplan
つまり、常に「見える化→承認→適用」の順序で進めます。
5-5-2. Planのアーティファクト化
-out
で固定化したPlanをアーティファクトとして保持すると、レビューと適用の同一性を担保できます。
したがって、Plan作成ジョブとApplyジョブは分離し、ハッシュで整合を確認します。
5-5-3. ガードレール(保護策)
- 本番ブランチは保護ルールと必須レビュー
- 破壊的変更が含まれる場合は追加承認
- 並列実行を抑止し、バックエンドのロックに必ず従う
5-5-4. 並列適用・部分適用の扱い
-target
は緊急回避の最終手段です。
なぜなら、依存関係を壊しやすいからです。計画的には、スタック分割と明確なモジュール境界でスコープを小さく保ちます。
5-6. ポリシーコードとガバナンス(Sentinel/OPAでのポリシー適用)
5-6-1. ポリシーコードの基本
Terraformの「ポリシー・アズ・コード」は、plan
結果をルールで評価し、違反を自動で弾きます。
つまり、人の記憶ではなくコード化された基準で統制します。
5-6-2. 代表ユースケース
- タグ必須(
Project
,Env
,Owner
が無いresource
を禁止) - 公開ポートの制限(0.0.0.0/0 の22/3389/80/443を禁止または例外審査)
- 暗号化必須(S3/GCS/ディスクの暗号化が有効でない変更を拒否)
- コスト制御(インスタンスタイプやディスクサイズの上限)
5-6-3. 運用への組み込み
- CIのPlan検証ステップでOPAやSentinelを実行
- レポートをPRに貼り、失敗はマージ不可
- 例外はチケット番号と期間を必須化し、期限切れで自動失効
その結果、Terraformの標準がチーム全体へ浸透します。
5-6-4. 段階的導入(監査→警告→ブロック)
最初は監査モード(違反をログのみ)で可視化。次に警告、最後にブロックへ引き上げます。したがって、開発体験を損なわずにガバナンスを確立できます。
トラブルシューティングとFAQ
Terraformのトラブルは多くが「認証」「依存関係」「ステート(状態)」「差分の理解不足」に集約されます。
つまり、原因ごとに切り分ければ、最短で復旧できます。ここでは実務で頻出のエラーをTerraform視点で整理し、再発を防ぐ運用知見までまとめます。
6-1. よくあるエラーと原因別対処(認証・依存関係・差分不一致)
6-1-1. 認証エラーの典型(AWS/Azure/GCP)
症状の例
- AWS: 認証情報が見つからない、期限切れ(環境変数/プロファイル未設定、MFA/一時クレデンシャル期限切れ)
- Azure:
az login
未実行、サブスクリプション未選択、SPの権限不足 - GCP: ADC未設定、サービスアカウント鍵のパス誤り、必要ロール不足
対処の要点
- TerraformのHCLに秘密は書かず、環境変数やCLIログイン、短命トークンで注入する。
- まず
terraform plan
で403/401系メッセージを確認し、該当クラウドCLIで再ログイン。 - 最小権限を原則に、
plan
用読み取りとapply
用書き込みを分離。 - CIでは「誰の権限で実行しているか」を明示(サービスアカウント/ロールアサインの棚卸し)。
6-1-2. プロバイダ初期化・取得失敗(terraform init
周り)
よくある原因
- バージョン制約の衝突(
required_providers
の指定とロックが不整合) - ネットワーク/プロキシでレジストリに到達できない
- 古いキャッシュや中途半端なプラグインが残存
対処
versions.tf
でTerraform本体とプロバイダのバージョン固定を徹底。- 依存が壊れたら
terraform init -reconfigure
で再初期化。 - どうしても更新が必要なら
terraform init -upgrade
を計画的に実施し、PRで差分確認。 - プラグインキャッシュ(
TF_PLUGIN_CACHE_DIR
)を使い、ネットワーク依存を軽減。
6-1-3. 依存関係エラー(参照ミスや循環)
症状
- 「未宣言リソースを参照」「循環参照(Cycle)」
対処
- 参照は「
resource.type.name.attr
」の正しいアドレスかを確認。 - 暗黙依存がないのに順序が必要なときだけ
depends_on
を使用。 - 大規模構成は
terraform graph | dot
などで依存可視化を行い、循環を排除。
6-1-4. 差分不一致・インポート関連(既存資源がある/無い)
症状
- 既に存在するリソースを新規作成しようとして失敗(名前競合)
- 逆に「存在しないのにインポートしようとしている」
対処
- 既存を生かしたいなら
terraform import
でステートに取り込み、その後plan
で整合確認。 - プロバイダのデフォルト付与で毎回差分が出る属性は、真に意図したものだけ
lifecycle { ignore_changes = [...] }
を検討。 - 名前やID生成ロジック(
format()
やrandom_*
)を固定化し、再作成の連鎖を回避。
6-1-5. ステートロック・競合
症状
Error acquiring the state lock
でapply
できない
対処
- 並行
apply
をやめ、CI/CDは直列化。 - バックエンドのロックを有効化(S3+DynamoDBなど)。
- どうしてもロックが残留した場合のみ、作業者全員の停止を確認した上で
terraform force-unlock <LOCK_ID>
を実行(最後の手段)。
クイック参照表:Terraformエラーと初動
症状 | 主原因 | 初動チェック | 代表的な解決策 |
---|---|---|---|
認証失敗 | 期限切れ/未設定 | CLIで現在の認証状態 | 再ログイン、環境変数注入、最小権限見直し |
init失敗 | 依存/ネットワーク | versions.tf とロック | -reconfigure 、必要に応じ-upgrade |
循環/参照エラー | 設計不備 | 参照先/depends_on | 参照見直し、設計分割、graph で可視化 |
既存衝突 | 命名/インポート不足 | リソース有無 | terraform import 、命名ポリシー統一 |
ロック取得失敗 | 並行実行 | 実行者とジョブ | 直列化、ロック設計、最終手段はforce-unlock |
6-2. 運用でハマりやすいケース集(ドリフト、破壊的変更、プロバイダ更新時)
6-2-1. ドリフト(手作業変更でステートと実体がズレる)
何が起きるか
Terraform外(コンソール操作など)で設定を変えると、plan
で毎回差分が出て不安定になります。
つまり、再現性が失われます。
避け方/直し方
- 原則「Terraformだけが変更する」体制にし、例外は申請制にする。
- 定期的に
terraform plan -refresh-only
で現状追従。 - 既存を採用したいなら
terraform import
、Terraform側に寄せたいなら適切なHCLへ修正。 - どうしても外部変更が多い属性は限定的に
ignore_changes
を使う(乱用は非推奨)。
6-2-2. 破壊的変更(置換が必要な属性の更新)
典型例
- サブネットやディスクのサイズ/タイプなど、プロバイダ上「置換(replace)」が必要な属性の変更。
- 名前変更やパス変更でアドレスが変わり、Terraformが新規作成→既存削除の順序を取る。
回避策
- まず
plan
で「-/+
(再作成)」記号を確認。 - 無停止要件があるなら
lifecycle { create_before_destroy = true }
を設定。 - リファクタ時は
moved
ブロックでステートを安全に移譲。
moved {
from = aws_s3_bucket.old
to = aws_s3_bucket.main
}
- 本番前に同型の下流環境で検証し、切替手順(Blue/Green等)を用意。
6-2-3. プロバイダ更新時のハマりどころ
何が起きるか
- スキーマ変更で不要な差分が大量発生、意図せず置換。
- 非推奨属性の既定値が変わり、
plan
にノイズが増える。
安全運用のコツ
required_providers
と.terraform.lock.hcl
で固定し、更新は定期メンテ窓で。- まず
terraform init -upgrade
で検証ブランチを作り、plan
差分をPRで共有。 - ノイズ属性には限定的な
ignore_changes
を当てるか、モジュール側で吸収。 - 破壊的変更が混じる場合は、メジャーアップ時の移行ガイドに従い、段階ロールアウト。
6-2-4. ワークスペース/環境分離の落とし穴
落とし穴
terraform.tfvars
やバックエンドのキーを誤って共有し、別環境を上書き。- ワークスペースでの変数差分が見えづらく、ヒューマンエラーに気づきにくい。
対策
- 環境ごとにバックエンド/ステートキーを明確に分離。
- 重要な値(
project
,env
,region
など)はoutput
で可視化し、plan
レビューで確認。 - 本番はワークスペースではなくディレクトリ/リポジトリ分割も検討。
6-2-5. FAQ(現場でよく聞かれるTerraformの疑問)
- Q.
-target
で部分適用して良いか?
A. 緊急時の回避策に留めます。依存崩れを招くため、恒常運用は避け、構成を適切に分割しましょう。 - Q. いつ
force-unlock
して良い?
A. 実行者全停止と安全確認後のみ。誤るとステート破損や二重適用に繋がります。 - Q.
ignore_changes
は便利だが常用して良い?
A. ノイズ削減には有効ですが、逸脱の温床です。対象属性を最小化し、理由をコードコメントに残すとよいでしょう。 - Q. モジュールの名前変更はどう進める?
A. まずmoved
でステート移譲し、plan
が置換にならないことを確認してから適用します。

IT資格を取りたいけど、何から始めたらいいか分からない方へ
「この講座を使えば、合格に一気に近づけます。」
- 出題傾向に絞ったカリキュラム
- 講師に質問できて、挫折しない
- 学びながら就職サポートも受けられる
独学よりも、確実で早い。
まずは無料で相談してみませんか?