Terraformの基本操作
宣言した値、保存した計画、state、実ファイルを別々に確認し、どの時点の値が反映されるか説明します。
説明
Terraformは宣言と管理対象の状態を比較し、変更計画を作ります。planは計画の作成、applyは変更の適用、stateは管理する資源と実体の対応記録です。ファイルを書き換えただけでは、管理対象へ反映されません。
local providerでapp.confと、その内容のハッシュを持つmanifest.txtを作ります。保存したplanを確認して適用し、入力を8080から9090へ変えて差分と実ファイルを比較します。対象は専用ディレクトリ内の2ファイルです。
宣言した値、保存した計画、state、実ファイルを別々に確認し、どの時点の値が反映されるか説明します。
1宣言を読む
portは8080が既定です。manifestのcontentはconfigのcontentを参照するため、資源間の依存関係になります。
cat main.tf変数・ファイル資源・参照関係を読むapp.confとmanifest.txtの2資源があります。file_permission=0600は作成するファイルの権限です。
2計画を保存する
plan.binに計画を保存します。inspect.pyはterraform show -jsonから資源ごとのactionsを抜き出します。
terraform plan変更計画を保存する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan資源別の変更を読む
python3 inspect.py dependency宣言内の依存参照を読む2資源ともcreateです。manifestのcontent_referencesにconfigが含まれ、参照が依存を作っていることも確認できます。
3計画だけではファイルを作らない
plan後の実ファイルの有無を確認します。
python3 -c管理対象ファイルがまだないことを確認する 'from pathlib import Path; print("config_exists="+str(Path("app.conf").exists()))'Falseです。変更計画の作成と、実際の書込みは別の操作です。
4保存した計画を適用する
確認したplan.binをapplyへ渡します。適用後にstateの資源一覧とファイルを読みます。
terraform apply保存した計画を適用する -input=false -no-color plan.bin > apply.log
terraform state list管理資源のアドレスを読む
cat app.conf manifest.txt実ファイルの内容を読む2資源がstateに登録され、app.confはport=8080です。manifestにはその内容から求めたSHA-256が入っています。
5同じ宣言なら差分はない
同じ入力で再度planします。
terraform plan適用後の状態を比較する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan変更不要のactionsを読む両方no-opです。変更する必要がない状態になっています。
6入力を変えて差分を確認する
terraform.tfvars.jsonでport=9090を指定します。local_fileのcontent変更は、このproviderではファイルの置換として計画されます。
python3 -c入力を9090へ変更する 'import json; json.dump({"port":9090},open("terraform.tfvars.json","w"))'
terraform plan新しい入力の差分を保存する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan置換対象を読む
cat app.confまだ変わっていない実ファイルを読む計画にはdelete,createが表示されます。apply前の実ファイルは8080のままで、まだ更新されていません。
7変更後の値とハッシュを照合する
新しい計画を適用し、実ファイルから別にSHA-256を計算します。
terraform apply変更計画を適用する -input=false -no-color plan.bin > apply.log
cat app.conf実際のportを読む
python3 -c実ファイルからハッシュを再計算する 'from pathlib import Path; import hashlib; digest=hashlib.sha256(Path("app.conf").read_bytes()).hexdigest(); print("manifest_matches="+str(Path("manifest.txt").read_text()=="config_sha256="+digest+"\n"))'port=9090、manifest_matches=Trueです。宣言の参照だけでなく、保存された2ファイルの整合を確認できました。
8入力の範囲外を拒否する
port=80を指定すると変数のvalidationに違反します。inspect.pyは実際のplanの終了値とエラー文を確認します。
python3 inspect.py invalid範囲外の値でplanが失敗することを確認する
cat app.conf拒否後に実ファイルが保持されたことを読むplanは終了値1で拒否され、実ファイルは9090のままです。妥当でない入力を反映する前に止められました。
まとめ
planは差分を作り、applyで実体を変更します。
資源間の参照は依存関係を作ります。
stateだけでなく実ファイルの値と整合も確認します。
操作履歴と解説を振り返れます。
Terraform 1.17.0 / hashicorp/local 2.5.3 / local backend
cat main.tfterraform {
required_providers {
local = {
source = "hashicorp/local"
version = "2.5.3"
}
}
}
variable "port" {
type = number
default = 8080
validation {
condition = var.port >= 1024 && var.port <= 65535 && floor(var.port) == var.port
error_message = "port must be an integer from 1024 to 65535."
}
}
resource "local_file" "config" {
filename = "${path.module}/app.conf"
content = "port=${var.port}\n"
file_permission = "0600"
}
resource "local_file" "manifest" {
filename = "${path.module}/manifest.txt"
content = "config_sha256=${sha256(local_file.config.content)}\n"
file_permission = "0600"
}
output "port" { value = var.port }terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan
python3 inspect.py dependencylocal_file.config create local_file.manifest create content_references=['local_file.config.content', 'local_file.config']
python3 -c 'from pathlib import Path; print("config_exists="+str(Path("app.conf").exists()))'config_exists=False
terraform apply -input=false -no-color plan.bin > apply.log
terraform state list
cat app.conf manifest.txtlocal_file.config local_file.manifest port=8080 config_sha256=732322f37243042be9e5af21441ccfeed748f1cc2dacce6a9cc8cf31b4207083
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py planlocal_file.config no-op local_file.manifest no-op
python3 -c 'import json; json.dump({"port":9090},open("terraform.tfvars.json","w"))'
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan
cat app.conflocal_file.config delete,create local_file.manifest delete,create port=8080
terraform apply -input=false -no-color plan.bin > apply.log
cat app.conf
python3 -c 'from pathlib import Path; import hashlib; digest=hashlib.sha256(Path("app.conf").read_bytes()).hexdigest(); print("manifest_matches="+str(Path("manifest.txt").read_text()=="config_sha256="+digest+"\n"))'port=9090 manifest_matches=True
python3 inspect.py invalid
cat app.confexit=1 validation=port must be an integer from 1024 to 65535. port=9090
演習完了