身為DevOps工程師,會Terraform也是很正常的(二) — Command多多益善

身為DevOps工程師
12 min readMar 18, 2022

--

在前一篇的Terraform教學文章中,除了跟大家介紹Terraform是一個什麼樣的工具外,也有提到三個使用terraform最關鍵的指令。

  1. terraform init
  2. terraform plan
  3. terraform apply
Photo by insung yoon on Unsplash

Terraform Commands

當然除了這幾個外,還有很多其他Command是有它一席之地的。這邊列出幾個介紹給大家。

  • validate
  • format
  • show
  • output
  • destroy
  • refresh

validate

在我們編寫好 .tf 設定檔後,我們可以使用以下 command來確認編寫上是否有語法錯誤。

$ terraform validate

若是有輸入錯誤的情況,會告知使用者哪一行出問題。如下圖:

format

在編寫完成後,若是跟其他組員合作,常常會有不同的code style。e.g. 空格數不同。此時可以藉由以下command來修改成一樣的格式與style。

$ terraform fmt

輸入前,兩個resource的filename前有著不同數量的空白。

resource "local_file" "A" {
filename = "/tmp/A"
}
resource "local_file" "B" {
filename = "/tmp/B"
}

輸入後,兩個resource的filename變成有相同數量的空白。

resource "local_file" "A" {
filename = "/tmp/A"
}
resource "local_file" "B" {
filename = "/tmp/B"
}

show

執行完 terraform apply後,若是有需要確認目前建立出來的資源狀態時,可以使用 terraform show 來顯示現在tfstate的狀態。

> 不過需要注意,這個是tfstate的狀態。如果我去把 /tmp/test 刪掉,再執行一次也是一樣的結果。

$ terraform show# local_file.myfile:
resource "local_file" "myfile" {
content = "abc"
directory_permission = "0777"
file_permission = "0777"
filename = "/tmp/test"
id = "a9993e364706816aba3e25717850c26c9cd0d89d"
}
Outputs:file-content = "abc"

output

顯示output的值

$ terraform output
file-content = "abc"
# terraform output <output_variable_name>$ terraform output file-content
"abc"

refresh

更新 tfstate檔案,去符合遠端的系統狀態。我們來試試看把terraform建立出來的檔案刪除後,是不是可以被偵測到。

刪除terraform apply建立的檔案

$ rm /tmp/test

來試試refresh

$ terraform refresh
local_file.myfile: Refreshing state... [id=a9993e364706816aba3e25717850c26c9cd0d89d]
Outputs:file-content = "abc"

讓我們用剛剛學到的 terraform show 來確認看看

$ terraform showOutputs:file-content = "abc"

我們的resource都不見了!!
沒錯terraform發現了這件事情,並且幫我們把tfstate給刷新了!

destroy

刪除tfstate中所定義的資源。與apply一樣,會先顯示出準備刪除的動作後讓使用者確認後並輸入 yes 才將資源刪除。由於我們剛剛手動的把檔案刪除了,所以這次的 destroy 沒有刪掉任何的resource。大家可以再試試看重新執行 apply 後執行的結果有什麼差別。

$ terraform destroy

Changes to Outputs:
- file-content = "abc" -> null
You can apply this plan to save these new output values to the Terraform state,
without changing any real infrastructure.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yesDestroy complete! Resources: 0 destroyed.

Terraform State

剛剛提到的Command中,有些Command都跟tfstate這個東西脫不了關係,我想大家當下應該都有個疑問,什麼是tfstate?

其實呢! 在執行terraform apply後,會建立出一個 terraform.tfstate 的檔案,這個檔案儲存了apply後產生的各個資源相關的資訊,讓terraform 能夠藉由此檔案對目前的部署狀態做確認。

這個檔案,並不建議直接藉由vim等各種編輯器直接人工修改,通常都是讓terraform自動產生與修改的,但若是今天有修改的需求,terraform也提供了command讓人針對tfstate做操作。

state list

單純列出目前建立出來的資源,但不包含詳細的內容。

$ terraform state list
local_file.myfile

state show

取得詳細的state資料

$ terraform state show <resource_name>

e.g.

$ terraform state show local_file.myfile
# local_file.myfile:
resource "local_file" "myfile" {
content = "abc"
directory_permission = "0777"
file_permission = "0777"
filename = "/tmp/test"
id = "a9993e364706816aba3e25717850c26c9cd0d89d"
}

state move

移動resource為不同的名稱或是轉移到不同的tfstate

terraform state mv <resource_name> <new_resource_name>

讓我們來舉個例子吧!

$ terraform state mv local_file.myfile local_file.newmyfile
Move "local_file.myfile" to "local_file.newmyfile"
Successfully moved 1 object(s).

此時再執行一次state list,可以發現tfstate中定義的resource name變了

$ terraform state list
local_file.newfiletest

此時任務還沒完成,必須要再將 terraform configuration file(.tf檔)的resource name也變成為新的,如果在此時直接執行 plan,terraform會因為configuration file 與tfstate不一致而判斷需要重新建立。

$ terraform plan
local_file.newmyfile: Refreshing state... [id=a9993e364706816aba3e25717850c26c9cd0d89d]
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:# local_file.myfile will be created
+ resource "local_file" "myfile" {
+ content = "abc"
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "/tmp/test"
+ id = (known after apply)
}
# local_file.newmyfile will be destroyed
# (because local_file.newmyfile is not in configuration)
- resource "local_file" "newmyfile" {
- content = "abc" -> null
- directory_permission = "0777" -> null
- file_permission = "0777" -> null
- filename = "/tmp/test" -> null
- id = "a9993e364706816aba3e25717850c26c9cd0d89d" -> null
}
Plan: 1 to add, 0 to change, 1 to destroy.───────────────────────────────────────────────────────────────────────────────Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

我們手動來將configuration file中的 myfile修改成newmyfile,如下範例

variable "content" {
type = string
default = "abc"
}
resource "local_file" "newmyfile" {
filename = "/tmp/test"
content = var.content
}
output "file-content" {
value = local_file.newmyfile.content
}

再次執行 plan,一切就正常了

$ terraform plan
local_file.newmyfile: Refreshing state... [id=a9993e364706816aba3e25717850c26c9cd0d89d]
No changes. Your infrastructure matches the configuration.Terraform has compared your real infrastructure against your configuration and
found no differences, so no changes are needed.

state pull

下載遠端的tfstate檔案。

terraform state pull

在預設的情況下,tfstate會存放在我們執行terraform command的機器上,但如果今天同時有很多人要維護這一份terraform的project,有一個人修改好了,先執行apply就會造成大家的tfstate所記錄的狀態不一致,為了預防這樣的情況發生,terraform支援了將tfstate存放在remote端,放在remote端後,只要有人執行 apply 就會自動更新remote tfstate,讓所有人都可以吃到最即時的tfstate。

state rm

當你不希望管理某項資源的時候,就可以藉由這個command將資源從tfstate中移除。(這麼做並不會將資源刪除,只是不歸這個tfstate管理)

terraform state rm <resource_name>

舉例來說,我們先來列出目前的state

$ terraform state list
local_file.newmyfile

移除掉local_file.newmyfile

$ terraform state rm local_file.newmyfile
Removed local_file.newmyfile
Successfully removed 1 resource instance(s).

此時我們state list,就會看不到任何資源

$ terraform state list$ ls /tmp/local
/tmp/local

但其實檔案仍然是存在的哦

$ ls /tmp/test
/tmp/test

這篇教學中,讓大家知道除了原本的terraform三本柱(init, plan, apply)外其他的Commands,還介紹了tfstate的機制。

你以為這樣這系列就結束了嗎?
那可就錯了
很感謝您的收看
如果教學中有哪邊不清楚都歡迎留言討論。

To Be Continued

--

--

身為DevOps工程師

目前在蓋亞資訊擔任DevOps Consultant。最近才從後端的世界轉成投向DevOps的懷抱,目前專注在Kubernetes, GitLab, DevSecOps的學習中。