🍋

terraform refreshは実体に沿ってstateを更新する

2021/04/18に公開
2

はじめに

terraform refreshコマンドについて解説している日本語記事があまり見当たらなかっため、挙動を調べてみました。

【追記】terraform apply -refresh-onlyについて

Terraform v0.15.4から、terraform apply -refresh-onlyが使用できるようになりました。

https://github.com/hashicorp/terraform/releases/tag/v0.15.4

terraform refreshの場合、確認表示が行われず一気に実行されますが、terraform apply -refresh-onlyであれば通常のapplyと同様に確認表示が行われ、yes入力後に実行されます。

-refresh-onlyオプションの使用が推奨されているので、そちらを使うようにしてください。

環境

  • Terraform v0.14.3

refreshのまとめ

  • 実体の内容に沿って、stateが更新されます。実体側が更新されることはありません。
  • stateのoutputは追加・更新されます。実体は更新したくない(applyはしたくない)がoutputを追加・更新したい、といった状況では便利です。

terraform refreshとは

公式ドキュメントでは、以下のように解説されています。

The terraform refresh command is used to reconcile the state Terraform knows about (via its state file) with the real-world infrastructure. This can be used to detect any drift from the last-known state, and to update the state file.

This does not modify infrastructure, but does modify the state file. If the state is changed, this may cause changes to occur during the next plan or apply.

日本語に訳すと以下の通りです。

terraform refreshコマンドは、Terraformが(状態ファイルを介して)知っている状態と、実際のインフラストラクチャを照合するために使用します。これにより、最後に認識した状態からのずれを検出し、状態ファイルを更新することができます。

これはインフラを変更するものではなく、状態ファイルを変更するものです。状態が変更されると、次の計画や適用の際に変更が発生する可能性があります。

検証の事前準備

tfファイルに以下のようなセキュリティグループをa〜eの5つ書き、いったんterraform applyします。

resource "aws_security_group" "a" {
  name = "a"
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "TCP"
    cidr_blocks = ["0.0.0.0/32"]
  }
}

次に、tfファイルの書き換えと、Terraform外でのリソース実体への操作を実施し、以下の状況を作り出します。

表中のCIDRの値は、ingressの80番ポートのcidr_blocksです。

tf state 実体
name = "a" "0.0.0.0/32" "0.0.0.0/32" "192.0.2.1/32"に更新
name = "b" "192.0.2.1/32"に更新 "0.0.0.0/32" "192.0.2.1/32"に更新
name = "c" "0.0.0.0/32" "0.0.0.0/32" resource無し
name = "d" resource無し "0.0.0.0/32" "0.0.0.0/32"
name = "e" resource無し "0.0.0.0/32" resource無し

applyの場合

参考までに、この状況下でterraform applyを行うと、以下の結果になります。

tfファイルの内容に沿って、実体とstateが更新されます。

tf state 実体
name = "a" "0.0.0.0/32" "0.0.0.0/32" "192.0.2.1/32"
->"0.0.0.0/32"に更新
name = "b" "192.0.2.1/32" "0.0.0.0/32"
->"192.0.2.1/32"に更新
"192.0.2.1/32"
name = "c" "0.0.0.0/32" "0.0.0.0/32" resource無し
->新規resourceを作成
name = "d" resource無し "0.0.0.0/32" "0.0.0.0/32"
->既存resourceを削除
name = "e" resource無し "0.0.0.0/32"
->resource情報を削除
resource無し

refreshの場合

terraform applyではなくterraform refreshを実施した場合は以下の結果になります。

実体の内容に沿って、stateが更新されます。実体が更新されることはありません。

tf state 実体
name = "a" "0.0.0.0/32" "0.0.0.0/32"
->"192.0.2.1/32"に更新
"192.0.2.1/32"
name = "b" "192.0.2.1/32" "0.0.0.0/32"
->"192.0.2.1/32"に更新
"192.0.2.1/32"
name = "c" "0.0.0.0/32" "0.0.0.0/32"
->resource情報を削除
resource無し
name = "d" resource無し "0.0.0.0/32" "0.0.0.0/32"
name = "e" resource無し "0.0.0.0/32"
->resource情報を削除
resource無し

refreshはoutputを更新する

また、terraform refreshでは、outputが更新されます。

以下のoutputをtfファイル上に追加し、terraform refreshを実行します。

output "sg_a_id" {
  value = aws_security_group.a.id
}

すると、stateファイルには以下の通り、outputが追加されます。

  "outputs": {
    "sg_a_id": {
      "value": "sg-089a2c3802237bdcf",
      "type": "string"
    }
  },

実体は更新したくない(applyはしたくない)がoutputを追加・更新したい、といった状況では便利です。

スマートラウンド テックブログ

Discussion

megane42megane42

「apply の場合」の name = "d" 行の state 列は、tf ファイルから定義を消しているので、

"0.0.0.0/32"
->resource情報を削除

が正しそうですかね?

Takashi YamaharaTakashi Yamahara

stateからは削除されて実リソースは削除されない、ということをおっしゃってますか?