Terraformでstateのロックを解除する方法、ロックを手動で行う方法

2023-03-27Terraform

はじめに

Terraform には自動的にステートをロックする機能があります。

terraform planterraform apply コマンドを実行したときに自動的にロックされるので、 普段意識して操作する事はありません。

チーム開発する際には Terraform のステートをクラウドサービス(AWS S3、GCP Cloud Storage、AWS DynamoDB など)を使って管理することが多いでしょう。

この場合、 terraform plan コマンド実行中に Ctrl + C などで強制停止してしまうと、クラウドサービス上にロックデータが残ってしまいます。
結果、以降の terraform planterraform apply コマンドを実行できなくなってしまいます。

これを解消する方法逆に明示的にロックを行い、チームメンバーに対して排他する方法 について紹介します。

検証環境

$ uname -moi
x86_64 MacBookPro16,1 Darwin

$ bash -version | head -n 1
GNU bash, version 5.1.8(1)-release (x86_64-apple-darwin20.3.0)

$ terraform --version | head -n 1
Terraform v0.13.7

ステートのロックを解除する方法

僕は GCP の Cloud Storage を使うことが多いのですが、中途半端にステートのロックが残ってしまった場合には gs://XXXXX といったステート管理バケット上にロックファイルが残ってしまいます。
こちらを直接削除してもいいのですが、 terraform コマンドにロック解除コマンドが提供されているのでこれを利用するのが良いでしょう。

$ terraform plan
Acquiring state lock. This may take a few moments...

Error: Error locking state: Error acquiring the state lock: writing "gs://YOUR_BUCKET/default.tflock" failed: googleapi: Error 412: At least one of the pre-conditions you specified did not hold., conditionNotMet
Lock Info:
  ID:        1626671963103164
  Path:      gs://YOUR_BUCKET/default.tflock
  Operation: OperationTypePlan
  Who:       genzouw
  Version:   0.13.7
  Created:   2021-07-19 05:19:20.743282 +0000 UTC
  Info:

Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.

こんなエラーが出て、一向にコマンド再実行できない場合には、以下のコマンドを実行します。

ポイントは上記メッセージの ID を保存しておき、コマンドの引数として指定するという点です

$ terraform force-unlock 1626671963103164

ステートのロックを手動で行う方法

terraform コマンドには force-unlock コマンドが用意されているのですが、 force-lock のようなコマンドがありません。

代わりにロックを行うためのツールが OSS で公開されているため、そちらを利用したいと思います

インストール

Go 言語で作成されているツールのようです。
以下のコマンドでインストールできました。

$ git clone git@github.com:minamijoyo/tflock.git
Cloning into 'tflock'...
cd tfremote: Enumerating objects: 64, done.
remote: Counting objects: 100% (64/64), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 64 (delta 31), reused 53 (delta 21), pack-reused 0
Receiving objects: 100% (64/64), 60.56 KiB | 427.00 KiB/s, done.
Resolving deltas: 100% (31/31), done.

$ cd tflock

$ go install

$ tflock --version
0.0.3

使い方

.terraform ファイルがあるディレクトリ( terraform init するディレクトリ )で tflock コマンドを実行するだけです。

$ ls -ld .terraform
drwxr-xr-x - genzouw 17 6 19:48 .terraform/

$ tflock
Backend reinitialization required. Please run "terraform init".
Reason: Backend configuration changed for "gcs"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

Changes to backend configurations require reinitialization. This allows
Terraform to set up the new configuration, copy existing state, etc. This is
only done during "terraform init". Please run that command now then try again.

If the change reason above is incorrect, please verify your configuration
hasn't changed and try again. At this point, no changes to your existing
configuration or state have been made.

Error loading the state: Initialization required. Please see the error message above.

エラーとなってしまいました。

terraform init してからもう一度。

$ terraform init
Initializing modules...

Initializing the backend...

Error: Error parsing credentials 'terraform-sa.json': invalid character 'e' in literal true (expecting 'r')

$ tflock
Backend reinitialization required. Please run "terraform init".
Reason: Backend configuration changed for "gcs"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

Changes to backend configurations require reinitialization. This allows
Terraform to set up the new configuration, copy existing state, etc. This is
only done during "terraform init". Please run that command now then try again.

If the change reason above is incorrect, please verify your configuration
hasn't changed and try again. At this point, no changes to your existing
configuration or state have been made.

Error loading the state: Initialization required. Please see the error message above.

エラーになってしまいました。原因わからず。

tflock コマンドのソースコードが置かれているリポジトリの説明を見ると。。。。

Currently, it is tested only with Terraform 0.15 + AWS S3 (locked with DynamoDB).
The tflock uses a state lock function as same as Terraform uses under the hood.
So other backend types may or may not work.

どうやら AWSS3DynamoDB だけが明確にサポートされている模様。

GCS ではだめみたいです。

AWS で動作を確認した結果を掲載できずすみません。

ひとこと

Terraform はステートファイル管理が面倒ですね。

Terraform をお使いの貴兄は、 このあたりのつらみはありませんか?

2023-03-27Terraform