Terraformは状態ファイル(tfstate)を単一の真実として扱うため、並行実行が衝突すると破損や消失が起きます。State Lockingはこれを防ぐための公式機構で、対応するバックエンドでは排他制御を自動で行います。
本稿では、バックエンド別のロック挙動、S3+DynamoDBの実装手順、衝突時の対処、CI/CDの直列化パターン、そしてAssociate/Pro試験で問われやすいポイントをまとめます。
Terraformはplan/apply/destroyなどの実行時に、対応するバックエンドがサポートしていれば状態ファイルに対してロックを取得します。これにより、別プロセスが同一状態を同時に更新することを防ぎます。ロックに失敗するとCLIは待機(-lock-timeoutで調整)するか、タイムアウトで失敗します。
バックエンドがロックを実装していない場合、二重実行は“最後に書いた方が勝つ”という危険な状態になり、状態の不整合やリソースの幽霊化を招きます。チーム・CI/CDでの運用では、必ずロック対応のリモートバックエンドを選ぶのが基本です。
ロック情報はバックエンドにより管理場所が異なります(例: S3ならDynamoDB、AzureRMならBlobのLease、Terraform Cloudならワークスペースの実行キュー)。一部バックエンドでは作業ディレクトリに.terraform.tfstate.lock.infoが出力され、衝突時の診断に役立ちます。
| バックエンド | ロック対応 | ロック実装/要件 | 備考 |
|---|---|---|---|
| local | いいえ | なし | 個人・検証用途のみ推奨 |
| s3 | はい(DynamoDB必須) | DynamoDBテーブルのパーティションキー=LockID | S3バージョニング/暗号化/KMSは強く推奨 |
| azurerm | はい | Blob StorageのLease | 追加の外部ストア不要 |
| gcs | はい | Cloud Storageの世代管理+条件付き書き込みを利用(Terraformが制御) | 外部ストア不要 |
| consul | はい | Consulセッションロック | Consulクラスターが必要 |
| http | いいえ | なし | 衝突回避は自前実装が必要 |
CI/CDでの二重実行とロックの流れ(S3 + DynamoDBの例)
ロック待機時間の指定例(衝突が起きやすい環境向け)
terraform apply -lock-timeout=5mロックの有無はバックエンド選定の決定要素です。チーム・CI/CDではlocalやhttpのようなロック非対応は避け、運用要件に応じてs3+dynmodb、azurerm、gcs、remote(Terraform Cloud)などを選びます。
S3はDynamoDBテーブルを併用して初めてロックが成立します。Azure BlobはLeaseにより排他が保証され、GCSは世代管理と条件付き書き込みにより衝突を防ぎます。Terraform Cloudのremoteバックエンドはワークスペース実行を直列化し、追加の外部ストアを不要にします。
代表的バックエンドの設定例(抜粋)
# S3 + DynamoDB
terraform {
backend "s3" {
bucket = "my-tfstate-bucket"
key = "env/prod/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}
# AzureRM (Blob Leaseによるロック)
terraform {
backend "azurerm" {
resource_group_name = "rg-tfstate"
storage_account_name = "sttfstate001"
container_name = "tfstate"
key = "env/prod/terraform.tfstate"
}
}
# GCS(世代管理+条件付き書き込み)
terraform {
backend "gcs" {
bucket = "tfstate-bucket"
prefix = "env/prod"
}
}
# Terraform Cloud(実行キューによる直列化)
terraform {
backend "remote" {
organization = "my-org"
workspaces {
name = "infra-prod"
}
}
}最も普及している構成はS3を状態ストアとし、DynamoDBでロックを提供するパターンです。これによりマルチランナーや複数開発者の同時実行でも安全性が確保できます。
実務ではS3のバージョニング/KMS暗号化/厳格なバケットポリシーを有効化し、DynamoDBテーブルはパーティションキー=LockID(String)の単純なテーブルを用意します。
必要なAWSリソース定義(例)
provider "aws" {
region = "ap-northeast-1"
}
resource "aws_s3_bucket" "tfstate" {
bucket = "my-tfstate-bucket"
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration { status = "Enabled" }
}
resource "aws_kms_key" "tfstate" {
description = "KMS for Terraform state"
deletion_window_in_days = 30
}
resource "aws_s3_bucket_server_side_encryption_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule { apply_server_side_encryption_by_default { kms_master_key_id = aws_kms_key.tfstate.arn, sse_algorithm = "aws:kms" } }
}
resource "aws_dynamodb_table" "locks" {
name = "tf-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute { name = "LockID" type = "S" }
}
# バックエンド設定(別ファイルやinit時の-varフラグで渡す)
# terraform {
# backend "s3" {
# bucket = "my-tfstate-bucket"
# key = "env/prod/terraform.tfstate"
# region = "ap-northeast-1"
# dynamodb_table = "tf-locks"
# encrypt = true
# }
# }ロック衝突時、Terraformは「Error acquiring the state lock」等と表示し、ロック保持者の情報(ID/Operation/Who/Created/Pathなど)を案内します。-lock-timeoutで十分に待機すれば多くは解消します。
実行プロセスのクラッシュ等で孤立ロックが残る場合は、terraform force-unlock <ID> を用いて手動解除します。解除前に本当に他のapplyが走っていないことを必ず確認してください。
エラーメッセージと解除コマンド例
# 典型的なエラー例(抜粋)
# Error: Error acquiring the state lock
# Details: Resource temporarily unavailable
# Lock Info:
# ID: 9a6e5e1f-4f0a-4c2a-9a9d-cb1b0e5d1234
# Operation: OperationTypeApply
# Who: runner@build-host
# Created: 2026-04-18 09:15:22
# Info: Working Directory: ., State: s3/env/prod/terraform.tfstate
# 手動解除(孤立ロックのみ)
terraform force-unlock 9a6e5e1f-4f0a-4c2a-9a9d-cb1b0e5d1234ロックは状態の同時更新を防ぎますが、パイプライン設計でも“同一ワークスペースを同時に触らない”工夫が必要です。環境ごとに状態を分離し(workspacesやディレクトリ分割)、同一環境に対するジョブは直列化します。
Terraform Cloudのremoteバックエンドを使うと、ワークスペースごとに実行が自動的に直列化され、キュー管理やRBAC、ポリシーガードレールも併用できます。セルフホストの場合はバックエンドのロック+CIのconcurrency機能で二重化対策をします。
GitHub Actionsでの直列化例 + Terraform Cloudバックエンド
# .github/workflows/terraform.yml(同一環境を直列化)
name: terraform
on: [push]
concurrency:
group: tf-prod # 同一グループは直列化
cancel-in-progress: false
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init -input=false
- run: terraform apply -auto-approve -lock-timeout=10m
# Terraform Cloudのremoteバックエンド
terraform {
backend "remote" {
organization = "my-org"
workspaces { name = "infra-prod" }
}
}Associate/Proでは、S3でロックを有効にするにはDynamoDBが必須、AzureRMはBlob Lease、remoteはキュー直列化、local/httpは非対応、といった基礎がよく問われます。また、-parallelismはロックではない点、force-unlockは最後の手段という運用判断も頻出です。
計画段階のplanでもロックは取得されるため、同一状態を読む処理同士の同時実行にも注意を払います。CIでは環境分離と直列化の二段構えで安全性を高めます。
オプション早見(Associate/Proで頻出)
# ロック関連
terraform plan -lock-timeout=5m
terraform apply -lock-timeout=10m
terraform force-unlock <LOCK_ID> # 孤立ロックの解除(慎重に)
# 並列度(ロックとは別概念)
terraform apply -parallelism=5Associate / Pro
問題 1
複数のCIランナーが同一のS3バックエンド上の状態を参照し、まれにapplyが衝突して失敗します。最小の変更で衝突を防ぐ推奨策はどれですか?
正解: A
S3バックエンドでの正規のロックはDynamoDBテーブルを併用したときに有効になります。バージョニングは復旧性向上でありロックではありません。-parallelismはリソース並列度で衝突回避になりません。状態ファイルを複数ワークスペースから共有するのも誤りです。
terraform planでもロックは取得されますか?
はい。planやrefresh、apply、destroy、importなど状態の読み書き・更新が絡む操作はロックを取得します(バックエンドが対応している場合)。showやstateファイルの単純表示など読み取りのみの操作はロックを取得しないことがあります。
-lock=falseを使っても大丈夫ですか?
推奨しません。緊急の復旧など、他プロセスが一切同時実行していないと厳密に保証できる場合に限るべきです。通常運用やCI/CDでの常用は状態破損のリスクが高いです。
孤立ロックを解除する正しい手順は?
まず本当に他のTerraform実行が動作していないことを確認し、必要なら関係者へ連絡・実行ログ確認を行います。その上で、エラーメッセージに表示されたロックIDを用いてterraform force-unlock <ID>を実行します。解除操作は監査ログに残し、直後のapplyは慎重に行ってください。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける
Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...
Terraform Authoring & Ops Pro: 上位資格の範囲と対策
上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...
Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす
Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...
Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義
Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...
Terraform Data Source徹底理解:既存リソースの参照で壊さず足す
Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...