Objects have change outside of Terraform の対応
IT技術
なぜこの記事を書くのか
terraformによるインフラの変更タスクの作業後、いざplan・applyしたときに、
身に覚えのない変更差分が出てきて焦ったことないですか?
私はあります。
こういった場面に遭遇した時に落ち着いて対応できるよう、
対処法をまとめておきたかったので、本記事を書こうと思いました。
本記事では、terraform外で変更があった時に表示される差分について整理していきます。
terraform外の差分はどんなときに表示されるのか
The Objects have change outside of Terraform is reporting a difference between the prior state and remote objects
HashiCorpのサポートページによると、「以前の状態」と「リモートオブジェクト」の差分を報告するとあります。
「以前の状態」とは、tfstateファイルの内容になります。
tfstateファイルはapplyする際に更新されるリモートオブジェクトの状態を表すファイルです。
「リモートオブジェクト」とは、リモートリソースの実体です。
つまり、「tfstateの内容と、リモートリソースの状態が違います」ということを教えてくれています。
以下、具体的なシチュエーションの例を上げていきます。
例1. リモートのリソースの設定値がコンソール上やcliで変更された
terraformで管理するリモートリソースがコンソールやcliなどによって変更された後に、terraform plan を実行すると「Objects have change outside of Terraform」のメッセージと共に、変更した分の差分が表示されます。
例2. プロバイダーによる更新
例) Cloud SQLの「利用可能なメンテナンスバージョン」
Cloud SQLのインスタンスをterraformで作成後、次回 terraform plan を実行するまでの間に、メンテナンスが実施されると、「Objects have change outside of Terraform」のメッセージと共に以下のようなような差分が表示されます。
1resource "google_sql_database_instance" "sample-dbinstance" {
2 ~ available_maintenance_versions = [
3
4 - "MYSQL_8_0_26.R20231105.01_03",
5
6 + "MYSQL_8_0_26.R20240207.00_07",
7
8 ]
Cloud SQLは定期的にメンテナンスが実施されます。その度に新しいメンテナンスバージョンが作成されます。
プロバイダーによって更新される設定値になります。
Cloud SQLのメンテナンスについて:Cloud SQL インスタンスでのメンテナンスについて
terraform外で変更差分がある状態で、applyした時の挙動
「Objects have change outside of Terraform」のメッセージが出ている状態で、ソースコードの変更を行わずにterraform apply した時の挙動は、設定値の種類によって変わります。
パターンは以下の2つです
- terraformのコード上で管理できる設定値
- terraformのコード上で管理できない設定値
1. terraformのコード上で管理できる設定値の場合
この設定値の差分は、apply時にリモートのリソースから削除されます。
terraformのソースコードの内容に合わせて、リモートリソースの設定が巻き戻るような挙動です。
リモートリソースの設定値は、terraformソースコードと同じ状態になります。
よってterraform apply 後に、terraform plan を実行すると「Objects have change outside of Terraform」のメッセージは出力されません。
2. terraformのコード上で管理できない設定値の場合
「terraformのコード上で管理できる設定値の場合」とは異なり、リモートリソースの変更は発生しません。
設定値がterraformによって自動で決定され、tfstateに反映されます。
結果、リモートリソースとtfstateの差分はなくなり、terraform plan 時の、「Objects have change outside of Terraform」のメッセージは表示されなくなります。
クラウドによる自動更新の例に挙げた「Cloud SQLの利用可能なメンテナンスバージョン」が、この設定値になります。
試しに、terraformソースコード上で「利用可能なメンテナンスバージョン(available_maintenance_versions)」を設定して、planを実行すると以下のエラーメッセージが得られます。
1│ Error: Value for unconfigurable attribute
2│
3│ with module.cloud_sql.google_sql_database_instance.sample-dbinstance,
4│ on ../../modules/sql/sample_cloud_sql.tf line 8, in resource "google_sql_database_instance" "sample-dbinstance":
5│ 8: available_maintenance_versions = [
6│ 9: "MYSQL_8_0_26.R20240207.00_07"
7│ 10: ]
8│
9│ Can't configure a value for "available_maintenance_versions": its value will be decided
10│ automatically based on the result of applying this configuration.
「available_maintenance_versions」は、terraformによって自動で決定される設定値なのでterraformソースコード上で設定できません。
このようなプロバイダーによって更新される値は基本的にterraformで管理するものではありません。
1│ Can't configure a value for "available_maintenance_versions": its value will be decided
2│ automatically based on the result of applying this configuration.
両者の違い
2つのパターンの違いとしては、terraform apply 時に、差分が「リモートリソースから削除される」か「リモートリソースに残る」になります。
- terraformのコード上で管理できる設定値→リモートリソースから削除される
- terraformのコード上で管理できない設定値→リモートリソースに残る
terraform apply後のterraform plan 時の差分は両者ともに無くなりますが挙動としては異なります。
どのように対応していくか
1. terraformのコード上で管理できる設定値の場合
まず、以下の2点を確認を確認し、対応します。
- terraform外で発生している差分が正しいかどうか
- 設定値を残すべきか・削除するべきか
具体的な対応
- 過去のタスクの内容や、変更を行った人に確認する
- その設定がされている目的の確認
- 残すにしても削除するにしてもチームに共有して実施
設定値を残す場合
リモートリソースの状態を「正」とする場合です。
該当する差分を、terraformのソースコードにも記載してterraform applyを実行しましょう。
設定値をコピペする場合は以下の手順でも可能です。
- terraform apply --refresh-only でtfstateをリモートリソースの状態に更新
2. terraform state show で、表示された状態からterraformのソースコードにコピペ
設定値を削除する場合
terraformソースコードの変更を行わずにterraform apply を実行し、terraformソースコードの状態にリモートリソースを更新する。
2. terraformのコード上で管理できない設定値の場合
この設定値の場合に、差分を無くしたいときは、以下のコマンドで、リモートリソース状態をtfstateファイルに取り込むのみになります。
terraform apply --refresh-only
terraform apply でも、設定値は自動で決定されるため、tfstateとリモートリソースの差分は無くなります。
しかし、やりたいこととしてはリモートリソースの状態をtfstateに取り込むのみで、リソースの変更を行う必要はないため、terraform apply --refresh-onlyで良いと思います。
ignore_changesはリモートオブジェクトの変更を無視するようには設計されていません。
「Objects have change outside of Terraform」で表示されている変更差分をignore_changesに指定しても、引き続き表示されます。
terraform外の変更差分として表示されている設定値をignore_changeブロックで指定してapplyすると、「terraform外で変更差分がある状態で、applyした時の挙動」で述べたように差分は無くなります。
しかし、terraform外でリモートリソースの設定値が変更されると、再び「Objects have change outside of Terraform」の差分として表示されます。
ignore_changesは、terraformソースコード上で設定した値を、次回以降、リモートリソースに反映しないようにするときに使用します。
例えば「リソースの作成自体はterraformで管理するけど細かい設定値はコンソールから変えたい」といったシチュエーションで使用します。
This note is to clarify that
ignore_changes
is not designed to ignore any changes that are coming in from the remote system. Theignore_changes
argument disables Terraform behavior of comparing the terraform configuration to the state in order to plan any necessary new actions. The “Objects have change outside of Terraform” is reporting a difference between the prior state and remote objects.
まとめ
差分がterraformで管理できる設定値である場合
- 差分を残す→terraformソースコードに差分を記載してapply
- 差分を削除する→terraformソースコードは変えずにapply
差分がterraformで管理できない設定値である場合
- terraform apply —refresh-only でtfstateにリモートリソース状態を取り込む
記事を書いてみて
作業に入る前に、planを実行して変更差分を綺麗にしておくことを習慣にしていこうと思いました。
作業前に差分に対して適切に対応することで、「あの設定、消えちゃったんだけど、、」とか「なんか設定追加されてる、、」とならないようにしたいです。
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
矢野健太郎です。 バスケットボールとお酒と漫画が好きです。 修行の日々です。
おすすめ記事
immichを知ってほしい
2024.10.31