terraform refreshは実体に沿ってstateを更新する
はじめに
terraform refreshコマンドについて解説している日本語記事があまり見当たらなかっため、挙動を調べてみました。
【追記】terraform apply -refresh-onlyについて
Terraform v0.15.4から、terraform apply -refresh-only
が使用できるようになりました。
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
「apply の場合」の
name = "d"
行のstate
列は、tf ファイルから定義を消しているので、が正しそうですかね?
stateからは削除されて実リソースは削除されない、ということをおっしゃってますか?