- 物理機リージョン/AZ
- ハイパーバイザVM exit で捕まえる
- VMゲストOS今ここ
- コンテナnamespace / cgroup
- プロセスアプリ / DB
宣言と世界のあいだには、比べる者が持つ記録があります。今回はその記録が、世界とどうずれるかを見ます。
まず結論
Terraform の state は、構成に書いたリソースと世界の実体を結ぶ対応表に、属性の写しを添えたものです。世界そのものではありません。
写しは plan や apply のたびに provider へ問い合わせて取り直されます(plan ではメモリ上だけ)。同じかどうかを決めるのは provider の読み取り(Read)で、手で中身を書き換えたファイルを「削除された」と写すこともあります。
Terraform で `hello` と書いたファイルを作り、その中身を手で `edited by hand` に書き換えました。構成は変えずに `terraform plan -refresh-only` を実行すると、何と報告されるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
state は世界ではなく、世界との対応表
Terraform が「このリソースは作ってある」と分かるのは、世界を見ているからではありません。手元の記録を読んでいるからです。文書はその記録、state の目的をこう書きます。
The primary purpose of Terraform state is to store bindings between objects in a remote system and resource instances declared in your configuration.
構成の resource "local_file" "greeting" と、世界のどの実体が同じものかを結ぶ対応表です。Purpose のページは、これが無いと成り立たないと書きます。
Terraform requires some sort of database to map Terraform config to the real world.
初期の試作では state を持たず、クラウドのタグで対応を取っていたが、すぐ問題に当たった、とも書いています(Early prototypes of Terraform actually had no state files and used this method. However, we quickly ran into problems.)。
対応表に加えて、state は属性値の写しも持ちます。こちらの扱いは軽いものです。
This is the most optional feature of Terraform state and is done only as a performance improvement.
必須なのは対応、任意なのは属性の写しです。写しは古くなるので、plan の前に取り直されます。
Prior to any operation, Terraform does a refresh to update the state with the real infrastructure.
- ・写しが更新されるのは Terraform が呼ばれたときだけ。それ以外の時間、state は最後に見た時点のまま
- ・「同じ実体か」を答えるのは Terraform 本体ではなく provider の読み取り
中身を手で書き換えたファイルは、どう写るか
hashicorp/terraform:1.16.4 のコンテナで、hashicorp/local 2.9.1 を使って1つのファイルを作りました。
terraform {required_providers {local = { source = "hashicorp/local" }}}variable "content" { default = "hello\n" }resource "local_file" "greeting" {filename = "${path.module}/out/hello.txt"content = var.content}
apply 後の state には "id": "f572d396fae9206628714fb2ce00f72e94f2258f" が記録されます。これは hello と改行の sha1 と一致します(python3 の hashlib で検算)。この provider では、中身がそのまま同一性の鍵です。ここで中身を手で書き換え、refresh-only の plan を取りました。
$ printf 'edited by hand\n' > out/hello.txt; cat out/hello.txtedited by hand$ terraform plan -refresh-only -no-colorlocal_file.greeting: Refreshing state... [id=f572d396fae9206628714fb2ce00f72e94f2258f]Note: Objects have changed outside of TerraformTerraform detected the following changes made outside of Terraform since thelast "terraform apply" which may have affected this plan:# local_file.greeting has been deleted- resource "local_file" "greeting" {- content = <<-EOThelloEOT -> null...(content_base64sha256 から filename までの9行を省略)- id = "f572d396fae9206628714fb2ce00f72e94f2258f" -> null}This is a refresh-only plan, so Terraform will not take any actions to undothese. If you were expecting these changes then you can apply this plan torecord the updated values in the Terraform state without changing any remoteobjects.
ファイルはあるのに has been deleted です。記録した id の実体を provider が見つけられなかった、という写り方です。provider 開発者向けの文書(Plugin Framework の Read)は、実体がもう無いときの扱いをこう勧めています。
Ignore returning errors that signify the resource is no longer existent, call the response state RemoveResource() method, and return early. The next Terraform plan will recreate the resource.
local provider の実装がこの指針に沿っているかは確かめていませんが、実演の出力はこの形と一致します。「無い」と判断するのは provider で、Terraform 本体ではありません。続けて通常の plan を取り、実物と state を確かめました。
$ terraform plan -no-colorlocal_file.greeting: Refreshing state... [id=f572d396fae9206628714fb2ce00f72e94f2258f]# local_file.greeting will be createdPlan: 1 to add, 0 to change, 0 to destroy.$ cat out/hello.txt # still hand-edited, plan changed nothingedited by hand$ grep -o '"id": "[^"]*"' terraform.tfstate # state file on disk untouched by plan"id": "f572d396fae9206628714fb2ce00f72e94f2258f"$ terraform apply -refresh-only -auto-approve -no-color | tail -4Apply complete! Resources: 0 added, 0 changed, 0 destroyed.$ grep -c local_file terraform.tfstate # after refresh-only apply0
読み取れることは3つです。通常の plan は「更新」ではなく 作成 を提案しました。plan の後も実物は書き換えたままで、ディスク上の state には古い id が残っています。apply -refresh-only を通して初めて、state から記録が消えました。同じ手順を2回流し、2回とも同じ出力でした。
実演で、中身を書き換えただけのファイルが `has been deleted` と写ったのはなぜだと考えられますか。
写しは、ずれていることが普通の状態
実演は、よく聞く2つの言い方がどちらも外れていることを示しています。
1つ目は「Terraform が状態を壊した」。plan は実物にも、ディスク上の state にも触れていません。チュートリアルは、plan のときの refresh について The refresh updates your state file in-memory と書きます。写しを取り直して比べただけです。
2つ目は「state を見れば実物が分かる」。書き換えた後も state には古い id が残っていました。state は Terraform が最後に見た時点の世界で、その後に誰かが手で変えた分は、次に呼ばれるまで写りません。
写しを世界に合わせる操作は、以前は単独の terraform refresh でした。現行の文書はこう書きます。
This command is deprecated. Instead, add the -refresh-only flag to terraform apply and terraform plan commands.
refresh-only モードの用途として、plan の文書は障害対応中に手で変えた場合を挙げ、reconcile Terraform's records with those changes と書きます。向きに注意してください。合わせるのは記録の側で、実物は戻しません。 自動で記録を合わせる危うさは、refresh コマンドの文書に書かれています。
If you have misconfigured credentials for one or more providers, Terraform may be misled into thinking that all of the managed objects have been deleted, causing it to remove all of the tracked objects without any confirmation prompt.
読み取りが失敗すれば、写しは「全部消えた」になりえます。写しの正しさは、読み取りの正しさを超えません。
逆に、Terraform の外で作った実体は対応表に無いので、Terraform からは存在しないのと同じです。チュートリアルは、AWS CLI で新しく作ったセキュリティグループを not tracked in the Terraform state file と表現しています。文書は管理下に入れる手段として import を挙げ、The block also declares an address for the imported resource in state. と書きます。対応を1行書き足す操作です。
Kubernetes は写しをどこに置くか
Kubernetes では、宣言と観測が同じオブジェクトの2つのフィールドとして説明されます。
The status describes the current state of the object, supplied and updated by the Kubernetes system and its components.
利用者が書くのは spec(望む状態)、status(今の状態)を書くのは Kubernetes 側の部品です。コントローラ(望む状態と今の状態を比べ、差を埋める制御ループ)について、文書はこう書きます。
The important point here is that the controller makes some changes to bring about your desired state, and then reports the current state back to your cluster's API server.
status もまた、誰かが観測して書いた写しです。だから「その写しがどの宣言を見て書かれたか」を示す欄があります。API の規約は observedGeneration を、宣言の変更に応じて動く部品が最後に観測した世代(generation)だと説明し、ensure that the reported status reflects the most recent desired status に使えると書きます。
違いは写しを書く者と時点です。Terraform では、呼び出した人の Terraform が plan や apply のたびに書きます。Kubernetes では、動き続けるコントローラが API サーバに書き戻します。
Kubernetes のオブジェクトで「今どうなっているか」を表す status は、誰が書くと文書に書かれていますか。
Terraform の state
呼び出されたときに provider が実物を読み、写しを取り直す。実演では、手で中身を変えたファイルを削除として写し、plan の後もディスク上の state には古い id が残っていた。
項目 Terraform写しの場所 terraform.tfstate(既定)書く者 呼び出した人の Terraform と provider書く時点 plan / apply のとき同一性の鍵 provider が決める(local_file は中身の sha1)
Kubernetes の status
宣言(spec)と同じオブジェクトに載り、Kubernetes の部品が書く。コントローラが現状を API サーバに報告し、observedGeneration がどの世代の宣言を見た写しかを示す。
項目 Kubernetes写しの場所 オブジェクトの status書く者 Kubernetes のシステムと部品書く時点 コントローラが観測して報告したとき鮮度の目印 observedGeneration
state と status はどちらも「今の世界」を表しているように見えます。どちらを読むときにも共通して確かめるべきことは何でしょうか。
その記録を書いたのは誰で、それは何秒前、何回前の操作のときだったかを考えてみてください。
この章のまとめ
- state の主目的は 構成のリソースと世界の実体を結ぶ対応表。属性の写しは
the most optional featureで性能のため。 - 写しは plan と apply のたびに provider が読んで取り直す。呼ばれていない間は古いまま。
- 何が「同じ実体」かを決めるのは provider。local 2.9.1 の local_file は、中身を変えたファイルを
has been deletedと写した。 - plan は実物もディスク上の state も変えなかった。「Terraform が壊した」も「state を見れば実物が分かる」も外れ。
terraform refreshは非推奨。-refresh-onlyが合わせるのは 記録の側で、実物は戻さない。- Kubernetes では宣言(spec)と観測(status)が同じオブジェクトに載り、status は Kubernetes の部品が書く写し。鮮度の目印は
observedGeneration。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
Terraform の文書が state の主な目的として挙げているのはどれですか。
用語集(4語)
- state(Terraform)
- 構成のリソースと世界の実体の対応表に、属性値の写しを添えた記録。既定ではローカルの terraform.tfstate に保存され、前の版が terraform.tfstate.backup に残る。
- refresh
- provider に実物を問い合わせて state の写しを更新すること。文書は plan と apply の前に行うと書く。単独の terraform refresh コマンドは非推奨。
- -refresh-only
- plan と apply のモード。Terraform の外で起きた変更に state を合わせることだけを目的とし、実物を元に戻す操作はしない。v0.15.4 以降。
- status(Kubernetes)
- オブジェクトの現在の状態を表すフィールド。宣言である spec と同じオブジェクトに載り、Kubernetes のシステムと部品が書く。
出典(一次ソース)
- Terraform — State(取得 2026-09-28。実演は Terraform 1.16.4) ↗
- Terraform — Purpose of Terraform State(取得 2026-09-28) ↗
- Terraform — terraform refresh command(取得 2026-09-28) ↗
- Terraform — terraform plan command, Refresh-only mode(取得 2026-09-28) ↗
- Terraform Plugin Framework — Read resources(取得 2026-09-28) ↗
- Terraform — Import resources overview(取得 2026-09-28) ↗
- Terraform — Tutorial: Manage resource drift(取得 2026-09-28) ↗
- Kubernetes — Objects in Kubernetes(Last modified 2025-11-24) ↗
- Kubernetes — Controllers(Last modified 2024-09-01) ↗
- Kubernetes API Conventions(kubernetes/community、2026-07-14 のコミット時点) ↗