Terraform

Terraform State Locking: 並行実行の衝突回避の実務と試験対策

2026-04-19
NicheeLab編集部

Terraformは状態ファイル(tfstate)を単一の真実として扱うため、並行実行が衝突すると破損や消失が起きます。State Lockingはこれを防ぐための公式機構で、対応するバックエンドでは排他制御を自動で行います。

本稿では、バックエンド別のロック挙動、S3+DynamoDBの実装手順、衝突時の対処、CI/CDの直列化パターン、そしてAssociate/Pro試験で問われやすいポイントをまとめます。

Terraform State Lockingの基本と並行実行の何が危ないのか

Terraformはplan/apply/destroyなどの実行時に、対応するバックエンドがサポートしていれば状態ファイルに対してロックを取得します。これにより、別プロセスが同一状態を同時に更新することを防ぎます。ロックに失敗するとCLIは待機(-lock-timeoutで調整)するか、タイムアウトで失敗します。

バックエンドがロックを実装していない場合、二重実行は“最後に書いた方が勝つ”という危険な状態になり、状態の不整合やリソースの幽霊化を招きます。チーム・CI/CDでの運用では、必ずロック対応のリモートバックエンドを選ぶのが基本です。

ロック情報はバックエンドにより管理場所が異なります(例: S3ならDynamoDB、AzureRMならBlobのLease、Terraform Cloudならワークスペースの実行キュー)。一部バックエンドでは作業ディレクトリに.terraform.tfstate.lock.infoが出力され、衝突時の診断に役立ちます。

  • plan/apply/destroy/import/moveなどはロックを取得する
  • ローカルバックエンドはロック非対応のため単独開発以外では非推奨
  • S3バックエンドはDynamoDBテーブルを併用して初めて堅牢なロックが有効
  • -lock=falseは緊急時以外使わない(状態破損リスク)
  • タイムアウト制御は-lock-timeout=5mなどで待機時間を延長
バックエンドロック対応ロック実装/要件備考
localいいえなし個人・検証用途のみ推奨
s3はい(DynamoDB必須)DynamoDBテーブルのパーティションキー=LockIDS3バージョニング/暗号化/KMSは強く推奨
azurermはいBlob StorageのLease追加の外部ストア不要
gcsはいCloud Storageの世代管理+条件付き書き込みを利用(Terraformが制御)外部ストア不要
consulはいConsulセッションロックConsulクラスターが必要
httpいいえなし衝突回避は自前実装が必要

CI/CDでの二重実行とロックの流れ(S3 + DynamoDBの例)

ロック取得要求Lock Denied (待機)Lock GrantedCI Runner Aterraform applyDynamoDB (LockID)S3 Buckettfstate (version)CI Runner Bterraform applyロック保持中はRunner Bは-lock-timeoutの範囲で待機し、ロック解放後に処理を継続/再試行する。

ロック待機時間の指定例(衝突が起きやすい環境向け)

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_tableを必ず設定。テーブルのパーティションキーはLockID(String)
  • AzureRM: 追加ストア不要。Blob Leaseにより排他が有効
  • GCS: バケット世代管理を前提にTerraformが安全な更新を行う
  • Remote(Terraform Cloud): 実行キューにより衝突を根本的に回避
  • HTTP/Local: ロック非対応。チーム/CIでは避ける

代表的バックエンドの設定例(抜粋)

# 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を状態ストアとし、DynamoDBでロックを提供するパターンです。これによりマルチランナーや複数開発者の同時実行でも安全性が確保できます。

実務ではS3のバージョニング/KMS暗号化/厳格なバケットポリシーを有効化し、DynamoDBテーブルはパーティションキー=LockID(String)の単純なテーブルを用意します。

  • S3バケット: バージョニング有効化、SSE-KMS推奨、削除制限ポリシー
  • DynamoDB: テーブル名をtf-locks等、パーティションキー=LockID(String)
  • Terraformバックエンド: dynamodb_tableを必ず指定
  • IAM: CI/CDロールにS3読書き+DynamoDB GetItem/PutItem/DeleteItem/UpdateItem権限

必要な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が走っていないことを必ず確認してください。

  • 待機を優先し、むやみに-lock=falseは使わない
  • 孤立ロックの解除は最後の手段。解除ログと監査を残す
  • CI/CDではリトライ戦略(指数バックオフ)と-lock-timeout延長を併用

エラーメッセージと解除コマンド例

# 典型的なエラー例(抜粋)
# 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

CI/CDでの並行制御パターン(実務と試験の両立)

ロックは状態の同時更新を防ぎますが、パイプライン設計でも“同一ワークスペースを同時に触らない”工夫が必要です。環境ごとに状態を分離し(workspacesやディレクトリ分割)、同一環境に対するジョブは直列化します。

Terraform Cloudのremoteバックエンドを使うと、ワークスペースごとに実行が自動的に直列化され、キュー管理やRBAC、ポリシーガードレールも併用できます。セルフホストの場合はバックエンドのロック+CIのconcurrency機能で二重化対策をします。

  • 状態の分離: env/prod, env/stageなどkey/prefix/workspaceで分ける
  • CIの直列化: 同一key/workspaceに対するジョブはconcurrencyで単一化
  • remote(Terraform Cloud)の実行キューで安全に直列化
  • -parallelismはリソース並列度であり、ロックとは別物(試験で混同注意)

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では環境分離と直列化の二段構えで安全性を高めます。

  • S3のロック= DynamoDBテーブル(LockIDキー)を設定
  • AzureRMはBlob Lease、GCSは世代管理+条件付き書き込み、Consulはセッションロック
  • local/httpはロック非対応。チーム/CIでは不適
  • -lock-timeoutで待機、-lock=falseは原則非推奨
  • -parallelismはリソース実行並列度でありロックとは別

オプション早見(Associate/Proで頻出)

# ロック関連
terraform plan   -lock-timeout=5m
terraform apply  -lock-timeout=10m
terraform force-unlock <LOCK_ID>   # 孤立ロックの解除(慎重に)

# 並列度(ロックとは別概念)
terraform apply  -parallelism=5

問題で確認

Associate / Pro

問題 1

複数のCIランナーが同一のS3バックエンド上の状態を参照し、まれにapplyが衝突して失敗します。最小の変更で衝突を防ぐ推奨策はどれですか?

  1. DynamoDBテーブル(パーティションキー=LockID)を作成し、バックエンド設定にdynamodb_tableを追加する
  2. S3バケットのバージョニングを有効化するだけにする
  3. terraform applyの-parallelismを1に設定する
  4. ワークスペースを1つ増やし、同じ状態ファイルを複数ワークスペースから参照する

正解: A

S3バックエンドでの正規のロックはDynamoDBテーブルを併用したときに有効になります。バージョニングは復旧性向上でありロックではありません。-parallelismはリソース並列度で衝突回避になりません。状態ファイルを複数ワークスペースから共有するのも誤りです。

よくある質問

terraform planでもロックは取得されますか?

はい。planやrefresh、apply、destroy、importなど状態の読み書き・更新が絡む操作はロックを取得します(バックエンドが対応している場合)。showやstateファイルの単純表示など読み取りのみの操作はロックを取得しないことがあります。

-lock=falseを使っても大丈夫ですか?

推奨しません。緊急の復旧など、他プロセスが一切同時実行していないと厳密に保証できる場合に限るべきです。通常運用やCI/CDでの常用は状態破損のリスクが高いです。

孤立ロックを解除する正しい手順は?

まず本当に他のTerraform実行が動作していないことを確認し、必要なら関係者へ連絡・実行ログ確認を行います。その上で、エラーメッセージに表示されたロックIDを用いてterraform force-unlock <ID>を実行します。解除操作は監査ログに残し、直後のapplyは慎重に行ってください。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Terraform

Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける

Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...

Terraform

Terraform Authoring & Ops Pro: 上位資格の範囲と対策

上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...

Terraform

Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす

Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...

Terraform

Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義

Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...

Terraform

Terraform Data Source徹底理解:既存リソースの参照で壊さず足す

Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...

Terraformの記事一覧 (102件)
© 2026 NicheeLab All rights reserved.