昨天我們聊到 Workspace 多環境管理,學會如何讓同一份 Terraform 程式碼安全地部署在 Dev、Test、Prod,並且讓不同環境互不干擾。這對於日常開發是很重要的,但在專案中,還有另一個也是讓人頭痛的問題:當我們修改資源或更新配置時,服務可能會短暫中斷,或者重要資源被意外刪掉。
Terraform 的 Resource Lifecycle 就派上用場了!我們可以透過 lifecycle
區塊,明確控制資源的建立、更新與銷毀順序,讓基礎設施運作更安全,也能強制執行策略,降低人為錯誤的風險~
Terraform 的生命週期規則(Life Cycle Rules)是一種 元參數(meta argument),用於在資源管理過程中定義特定的行為和條件。它能幫助我們自動化流程、最小化停機時間、防止意外破壞,並確保配置策略被嚴格執行。
在實務上,最常用的規則包括 create_before_destroy
、prevent_destroy
、ignore_changes
、replace_triggered_by
,還有最近新增的前置條件與後置條件。接下來我們就分別來看每個規則的實際作用!
想像一下,我們在雲端上有一台 Web 伺服器,然後突然想把機器規格升級。預設情況下,Terraform 會先刪掉舊的 VM,再建立新的 VM。但如果網站正在運行,使用者就會遇到短暫的中斷,這樣等於是大幅減少使用者體驗!
像這種情況,我們就可以使用 create_before_destroy
來解決這個問題。它確保新的資源先被建立,並確認運行正常後,再會刪除舊的資源。
它的配置像以下這樣:
resource "google_compute_instance" "web" {
name = "web-instance"
machine_type = "e2-medium"
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
network = "default"
access_config {}
}
lifecycle {
create_before_destroy = true
}
}
我們只要透過這個設定,當在修改 machine_type
後,Terraform 會先建立新的 VM,確認新機器正常啟動後,才會刪掉舊 VM。這樣就能達到服務不中斷,用戶甚至感受不到切換過程!
在雲端上有些資源比 VM 更為重要,比如資料庫或關鍵儲存。但如果不小心刪掉,後果是不是就非常嚴重!(光想到就覺得毛骨悚然)這時候我們就需要 prevent_destroy
:
resource "google_sql_database_instance" "primary" {
name = "prod-db"
database_version = "POSTGRES_14"
region = var.region
settings {
tier = "db-custom-2-7680"
}
lifecycle {
prevent_destroy = true
}
}
配置啟用後,當遇到有人執行 terraform destroy
或者錯誤操作修改某些欄位,Terraform 都會拒絕刪除並報以下錯誤:
Error: Instance cannot be destroyed
Resource google_sql_database_instance.primary has lifecycle.prevent_destroy set
這就像在重要資源上加了一把鎖,必須先移除設定才能刪除。這個小細節在生產環境中非常重要,能防止「一鍵毀滅」的悲劇!
有些屬性如果不希望被 Terraform 管理,例如:自動生成的 IP 或由其他系統自動維護的標籤。這時候我們可以用 ignore_changes
告訴 Terraform 忽略這些欄位,避免每次執行 apply
都觸發更新:
resource "google_storage_bucket" "critical_data" {
name = "company-critical-backup"
location = "US"
lifecycle {
prevent_destroy = true
ignore_changes = [labels]
}
}
這個配置在實務中是非常常見的。例如在自動化備份系統或標籤策略中,就能避免不必要的變更導致意外操作~
當資源之間有依賴關係時,某個資源變更可能會影響其他資源。replace_triggered_by
可以自動觸發替換相關資源,確保依賴一致性:
resource "azure_rm_storage_account" "example" {
name = "examplestorage"
resource_group_name = azure_rm_resource_group.example.name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
lifecycle {
replace_triggered_by = [azure_rm_resource_group.example.id]
}
}
當 Resource Group ID 改變時,Storage Account 也會被自動替換,能避免依賴錯亂。
Terraform 的前置條件(precondition
)和後置條件(postcondition
)是資源生命週期中的檢查機制,幫助我們在部署前後驗證資源狀態,確保符合策略與需求。
precondition
前置條件會在資源建立之前執行,用來檢查輸入參數或環境是否符合預期。例如,我們可以檢查資源位置是否在允許的列表中:
resource "azurerm_resource_group" "example" {
name = "example-rg"
location = var.location
lifecycle {
precondition {
condition = contains(var.allowed_locations, var.location)
error_message = "Location '${var.location}' is not allowed. Valid locations: ${join(", ", var.allowed_locations)}"
}
}
}
使用前置條件,我們可以在計畫階段就阻止錯誤配置的建立,避免違反組織政策或依賴資源狀態不符合要求。
postcondition
後置條件則在資源建立或更新後檢查,驗證資源的實際狀態。例如,確保 VM 已分配公共 IP,或不使用已淘汰的規格:
resource "azurerm_virtual_machine" "example" {
name = "example-vm"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
lifecycle {
postcondition {
condition = self.public_ip_address != null
error_message = "VM must have a public IP address assigned"
}
postcondition {
condition = self.vm_size != "Standard_A0"
error_message = "VM size Standard_A0 is deprecated and not allowed"
}
}
}
透過後置條件,我們可以在 apply 階段及時捕捉問題,確保資源符合安全規範或實際運作需求!
使用 lifecycle 時要注意以下幾點:
create_before_destroy
會讓新舊資源短暫並存,可能增加成本。prevent_destroy
並非永久鎖定,只要移除設定即可刪除資源。create_before_destroy
(例如需要唯一名稱的資源)。今天我們看到 Terraform Resource Lifecycle 保護基礎設施、避免意外的重要機制。透過設定 create_before_destroy
,我們可以在更新資源時避免服務中斷;利用 prevent_destroy
,可以防止關鍵資源被意外刪除;ignore_changes
能幫助我們忽略那些不必要的變更,保持資源穩定;replace_triggered_by
則確保了依賴資源之間的一致性;而前置條件與後置條件(precondition / postcondition)則可以在資源建立前後進行檢查,確保資源狀態符合預期。這些規則雖然看起來只是小細節,但在生產環境中往往能一命,也能讓 Terraform 專案更安全、更可控!