🔥

terraform state 理解してないのにterraform apply している人、危機感持った方が良いって

2024/03/14に公開
2

はじめに

茶番
terraform state 理解してない人、
俺、ガチで危機感持った方がいいと思う。
terraformerとして危機感持った方がいい
それこそが、お前がどう足掻いたって、apply出来ない理由だと思う。
apply出来ないって、これまでに一度もterraform state向き合ってこなかったら、厳しいって、明らかな事実だと思う。
俺には俺は向いてないから理解力ないから、家に引きこもってる方が楽しいから、俺はゲームが好きだから、やばいって。
何がやばいかっていうと、terraformerとして成熟しないんだよね。
その人生の中で、なんかしらの競争をしてないと、terraformerとして成熟するためのパーツに欠けるんだよね。
お前最後にapplyしたのいつ?terraformに理不尽なエラー言われたのいつ?ないでしょ
そういう経験ないと弱いって、絶対メンタル弱くなるって
勝負の世界に来たことがないterraformerは、自分のプライドが傷つけられたことがないよとか、
他のterraformerに負けたっていう悔しさを持ったことがない、弱いって、メンタルの強さがないんだもん、
お前最後に腹から声出したのいつよ?
一日家引きこもって、※※※※ ボソボソ喋ってんなよ、まじで
全部state 理解してないから、明らかに勝ち負けの世界で戦ったことがないからよ。
自分のプライドに傷が入るような状況に置かれたことがないからよ。
だからすぐにああ俺はダメなんだ またボソボソ喋り始める。
文句を言う、ちょっと理不尽なことあったら耐えられない、いや世の中は理不尽だって。うん。理不尽よね。違う?

以上、ガバガバ構文でした。お付き合いいただきありがとうございました。

こんばんは、スポーツ経験がない、危機感持った方が良い側の小見です。
(語気の強いタイトル失礼しました、オマージュ元は危機感ニキでお調べください。)

さて、今回はTerraformのstateについてまとめていこうと思います。
※今回は便宜上AWSの利用を想定しています。

対象読者

  • なんとなーくterraform applyしていて、なんとなーくローカルにterraform.stateファイル出来上がっているけど深く理解できない初学者さん
  • 既存のterraformコードを少し弄ってterraform applyをしている方
    • この場合、stateファイルの存在も把握していないかもしれません。(自分はこのパターンでした。)

危機感持った方が良いって

はじめに、何故危機感を持った方が良いのか少し前置きをさせて下さい。
例えば、チーム開発時にstateファイルがローカルに保存されている場合、
複数名でapplyしてしまうと、resourceが2つ生成されることがあります。
また、ローカルに保存している関係で、担当者が端末を交換したときにstateファイルを失ってしまったりと言ったリスクもあります。

その他にも、間違えてstateファイルを削除してしまったりすると、復旧が大変です。
コードとAWS上のresourceの紐付け作業が大変だったり、
resourceの種類によっては復旧が出来ないものあります。
例えば以下の様なresourceは復旧が出来ずapplyし直しが必要だったりします。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment

terraform stateとは?

主な役割としては、terraformコード上のresourceとAWS上のarnなどとマッピングです。
例えば、EC2などterraform applyした後に発番されるarnがわからないと、修正して再度applyする時やdestroyするときなど、どのEC2を削除して良いか分からなくなります。
これを解消するためにterraform stateが存在しています。

その他の役割について知りたい方は、公式ドキュメントをご覧ください。

触って理解する

ここからはハンズオン形式で、触ってterraform stateについて理解していきましょう。

下準備

お金もかからない、作成に時間がかからない、iam roleで説明していきます。
以下ファイルをご準備ください。

main.tf
resource "aws_iam_role" "test" {
  name               = "test"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      }
    }
  ]
}
EOF
}
# ご自身の ~/.aws/credentials に登録されているprofileを記述してください。
# 恐らくprofileが一つだけの初期設定の場合は"default"で大丈夫だと思います。
provider "aws" {
  profile = "default"
}

apply

applyをしてAWS上にroleを作成しましょう。

$ terraform apply

以下の様に問われるのでyesと入力しましょう。

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: 

terraform.tfstateを確認する

applyが完了すると実行したディレクトリにterraform.tfstateが生成されています。
このファイルを確認してみて下さい。

attributesのarnに今回applyしたroleのarnが記載されてまして、
これが前述したAWS上のresourceとのマッピングです。

また、後述しますが、terraform.tfstateは基本的にローカルに保存しないため、ファイルの確認が手間ですので、コマンドで確認することができます。
以下よく使う2つのコマンドで確認できるので、これは覚えておくと色々と便利です。

terraform state list

state の一覧表示が出来ます。
実行すると、コード上のresourceの数だけlist表示されます。

$ terraform state list       
aws_iam_role.test

ここで表示されるresource名のルールは、
terraformのresource名、今回だと、aws_iam_role
自分でつけた、resource名、今回だと、test
これらを.で繋げたのが、resource名となります。

また、moduleを利用している場合、

module.自分で付けたモジュール名.terraformのresource名.自分で付けたresource名

となり、このルールが最初わからず、またドキュメントを見つけられず苦しみました。

例)
module.main.aws_iam_role.test

terraform state show resource名

state の詳細を閲覧することが出来ます。
ここで表示されるのは、ほぼコード上の表現に近いものなので、ここで出力された内容をもとにterraformのコードを書くのが個人的に楽です。

$ terraform state show aws_iam_role.test
# aws_iam_role.test:
resource "aws_iam_role" "test" {
.....

state を消してみる

rm コマンドで、stateを消すことも可能です。
terraformのディレクトリ構成見直しの時や、開発途中で一時的にterraformで管理したくない。と言った時に利用できます。
※terraformの管理対象外になるので、実行には注意して下さい。再度管理対象にする方法を後述しますが、そもそもなんのresourceを取り扱っていたのか(arn)は、別途記録しておく必要があります。

$ terraform state rm aws_iam_role.test
Removed aws_iam_role.test
Successfully removed 1 resource instance(s).

再度terraform state listを実行しても何も表示されないことが確認できると思います。

import してみる

import をすることで、rmしてしまったresourceや、`元々terraformの管理対象外だったAWSのresourceをterraformの管理対象にすることが出来ます。

importの構文は、特殊でresourceの種類ごとにarnを指定したりnameを指定したりマチマチなので、都度resourceの公式ドキュメントを確認しましょう。
基本的に、resourceドキュメントの一番下に記載されています。

今回は、こちらになります。

$ terraform import aws_iam_role.test test
aws_iam_role.test: Importing from ID "test"...
aws_iam_role.test: Import prepared!
  Prepared aws_iam_role for import
aws_iam_role.test: Refreshing state... [id=test]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

terraform destroy

最後にお片付けです。

$ terraform destroy

チーム開発時のterraform.tfstate管理について

ここまでお付き合い頂いた方の中に、terraform.tfstateファイルなんて見たことないよ?という方がいらっしゃると思います。
基本的にチーム開発時にterraform.tfstateファイルはローカルに配置せずS3などに配置します。
terraformは、コード上のbackend設定を読み込みterraform init時に自動的にS3への初期設定を行なってくれます。
その後は、applyやdestroyなど実行した後、自動的にS3への更新も行なってくれます。
これが、今まで見たことないよ〜という原因になります。

terraform initで読み込む関係で、backendに関しては変数とかで、良い感じに切り替えると言ったことが出来ないはずです。(出来る場合お教えください。)

設定例は以下になります。

backend.tf
terraform {
  backend "s3" {
    bucket  = "バケット名"
    profile = "default"
    key     = "test"
    region  = "ap-northeast-1"
    encrypt = true
  }
}

追記
tak458様より、init時にbackendの値を注入する方法をコメントいただきました。
ありがとうございます!
https://zenn.dev/link/comments/969053ab1be548


まとめ

個人的には、terraform stateってterraformを理解する上で最重要項目だと思っているのですが、意外と説明されている記事が少なかったのでハンズオン形式でまとめてみました。
terraform毎回なんとなく触って毎回ドキドキしていると言った方などの一助になれば幸いです。

宣伝

スペースマーケットではエンジニア募集しております!

https://www.wantedly.com/projects/1113570

弊社は人と文化が良いなと個人的には感じておりますのでこちらも併せて読んでいただけますと嬉しいです。
https://spacemarket.co.jp/recruit/engineer/

スペースマーケット Engineer Blog

Discussion

ピン留めされたアイテム
tak458tak458

terraform initで読み込む関係で、backendに関しては変数とかで、良い感じに切り替えると言ったことが出来ないはずです。(出来る場合お教えください。)

下記リンク先で説明されている感じで別ファイルに切り出してコマンド引数に指定することで同等なことができると思いますがどうでしょうか?
https://developer.hashicorp.com/terraform/language/settings/backends/configuration#partial-configuration

backend.hcl
    bucket  = "バケット名"
    profile = "default"
    key     = "test"
    region  = "ap-northeast-1"
    encrypt = true
backend.tf
terraform {
  backend "s3" {}
}
terraform init -backend-config="backend.hcl"

それとも plan 時などに適宜変数で入れ替えるということでしょうか?たしかにそれは出来ないと思いますので、私も知りたいところです。

seiji_omiseiji_omi

コメントいただきありがとうございます!
頂いた方法を存じ上げておりませんでした。
手元で試したところ、切り替えに成功しましたため、記事にリンクをつけさせて頂きました。
感謝です。

それとも plan 時などに適宜変数で入れ替えるということでしょうか?たしかにそれは出来ないと思いますので、私も知りたいところです。

どちらかと言うとこちらのニュアンスが強かったのですが、
とはいえ頂いた方法もbackend管理の一つの選択肢になり得ると思います。