Terraform Cloudでのtfstateの分割方法
この記事の想定読者
- 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のみ利用するシンプルなコードで試してみます。
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 mv
➜ mv 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
と rp2
が source.tfstate
から dest.tfstate
に移動したことが確認できました。
source.tfstate
をTerraform Cloudにpushする
6. 分割した ここまでで分割作業は完了ですが、あくまでローカルで作業していただけなので、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.rp1
と random_pet.rp2
を削除すれば完了です。
( No changes
と表示されるようになれば修正完了です。)
参考
How to Split State Files
Discussion