💔

Terraform Cloudでのtfstateの分割方法

2023/11/28に公開

この記事の想定読者

  • Terraform Cloudを使ったことがある人。
  • Terraform CLIを使ったことがある人。
  • 以下のいずれかに近い状況にある人。
      - Terraform Cloudを(そこそこ)使っており、当初は快適だったものの、ここのところどうもplanやapplyに時間がかかるなあ。。。どうにかできないかなあ🤔。。。と思っている人。
    • 深く考えずにTerraform Cloudを使い始めたが、Workspaceが肥大化してきてしまいもう少し小さい単位で管理したいなあ🤔。。。と思っている人。

tfstateの分割?

そもそもtfstateとは?(復習)

Terraformでは、実行結果として作成されたインフラの状態を、tfstateファイルの中に保存しているのはみなさんご存知だと思います。
このファイルはTerraformが変更管理をするために利用されるため、非常に重要なもので、Terraform Cloudをbackendとして使っている場合にはTerraform Cloudに保存されます。

このtfstateを見て、前回何を作ったかをTerraformが思い出せるようにしておかないと、次にTerraformが動いた際に全く同じ構成で全く同じインフラを作ろうとしてしまいます。

単純にインフラ作成の自動化をするだけで、作った後のことは知りません!という場合には気にしなくてもいいかもしれませんが、まあそんなことはないと思いますので、TerraformでのIaC実現にはこのtfstateの扱いがついて回ることになります。

tfstateの分割とは?

これはそのままの意味で、tfstateを複数にバラすことを意味します。
tfstateはTerraformのWorkspaceごとに一個作成されるため、tfstateの分割=Terraform CloudのWorkspaceの分割=Terraformの管理・実行単位を小さくすることを意味します。

分割したくなるシチュエーション

ここまでくると想像に難くないかなと思いますが、分割したくなるシチュエーションとしては、「Terraformの実行時間を短くしたい」につきます(個人の意見です)。
tfstateが肥大化する=Terraformのワークスペース(実行の単位)で管理しているリソースの思い出しに時間がかかるため、ちょっとした修正をサクッと入れたい場合にも、planだけでやたら時間がかかる、、、なんてことがおこってしまいます。

tfstateを分割

では実際にtfstateを分割してみましょう。

0. 事前準備

必要なもの

  • Terraform Cloudアカウント
  • GitHubアカウント
  • terraform commandのインストールされたPC

1. サンプルコードの準備

今回はtfstateを分割してみることが目的なので、random providerのみ利用するシンプルなコードで試してみます。
https://github.com/taromurata/state-mv-demo-pub

Forkするなりコピーするなりでご利用ください。

2. Terraform Cloudでプロビジョニングしてtfstateを作成する

VCS-driven Workspaceを作成し、先ほどのリポジトリを紐づけ、一旦Runします。

無事に random_pet リソースが4つ作成されました。

3. Workspaceのロック

どこかの誰かが意図せずstateを変更しないように、ワークスペースはLockしておきましょう。

4. tfstate取得

Terraform CloudのWorkspaceからtfstateを取得する方法はいくつかありますが、ここでは terraform state pull を使ってやってみます。

新しく作業ディレクトリを作成し、移動したのちに、以下のようなファイルを準備します。
(CLI-driven Workspaceでつかういつものコードです。)

terraform {
  cloud {
    organization = "<YOUR_TFC_ORG_NAME>"

    workspaces {
      name = "<YOUR_TFC_WS_NAME>"
    }
  }
}

ファイルが準備できたら、そこで terraform init > terraform state pull でtfstateを取得します。

➜ terraform init
➜ terraform state pull > source.tfstate

5. 分割

分割を始める前に、改めて作業ディレクトリを作成し、source.tfstateを移しておきます。

mkdir mvmv source.tfstate mv/

現在のstateには4つのリソースが存在しています。

➜ terraform state list -state=source.tfstate
random_pet.rp1
random_pet.rp2
random_pet.rp3
random_pet.rp4

ここから、半分を別のtfstateに移動してみます。
tfstateの分割(=リソースを別のtfstateに移動する)を行うには、 terraform state mv コマンドを使います(https://developer.hashicorp.com/terraform/cli/commands/state/mv)。

ls                  
source.tfstate  terraform.tf

➜ terraform state mv -state=source.tfstate -state-out=dest.tfstate random_pet.rp1 random_pet.rp1
Move "random_pet.rp1" to "random_pet.rp1"
Successfully moved 1 object(s).

➜ terraform state mv -state=source.tfstate -state-out=dest.tfstate random_pet.rp2 random_pet.rp2
Move "random_pet.rp2" to "random_pet.rp2"
Successfully moved 1 object(s).

移動できていることを確認してみます。

➜ terraform state list -state=source.tfstate
random_pet.rp3
random_pet.rp4

➜ terraform state list -state=dest.tfstate  
random_pet.rp1
random_pet.rp2

想定通り、 rp1 と rp2source.tfstate から dest.tfstate に移動したことが確認できました。

6. 分割した source.tfstate をTerraform Cloudにpushする

ここまでで分割作業は完了ですが、あくまでローカルで作業していただけなので、Terraform Cloudにpushし直す必要があります。

まず、テキストエディタで編集後の source.tfstate を開き、 serial の値を、元の source.tfstate の値+1にします。

次に、 terraform.tf が配置されているディレクトリに戻り、 source.tfstate をそのディレクトリに移動させます。

ls
mv/             source.tfstate  terraform.tf

➜ head -n4 source.tfstate 
{
  "version": 4,
  "terraform_version": "1.6.4",
  "serial": 2,

準備ができたら、 terraform state push で分割したtfstateをTerraform Cloudにpushします。
-lock=false オプションを使ってpushする際には、その間に誰かがstateをいじらないようにしましょう。)

➜ terraform state push -lock=false source.tfstate

Terraform Cloudのコンソールから、新しいtfstateが確認できるはずです。

ここまできたら、WorkspaceのLockを解除します。

7. コードの修正

分割はこれで完了ですが、このままapplyしようとすると、先ほど分割した(消した)リソースを改めて作ろうとしてしまいます。
これでは達成したかったtfstateの軽量化が達成できませんので、コード側も合わせて修正する必要があります。

今回の例では、 random_pet.rp1random_pet.rp2 を削除すれば完了です。
No changes と表示されるようになれば修正完了です。)

参考

How to Split State Files

Discussion