昨天我們聊到 Functions 與 Locals,學會了怎麼讓程式碼更乾淨、好維護。
今天要來看看 Terraform 的另一個面向:怎麼跟外部世界互動。
在實務上,我們有時候需要 Terraform 做一些「額外動作」,或是讀取「Terraform 本身沒辦法直接拿到的資訊」。這時候就會用到 Provisioners 跟 External Data Source。
Provisioner 可以想像成「附加動作」:當 Terraform 建立或刪除資源時,額外執行一段 script 或命令。
local-exec
→ 在 本機 執行命令。remote-exec
→ SSH 連到遠端 VM 執行命令。有時候如果需要在完成某些事情時能推播讓夥伴們知道就可以這麼做:
resource "google_compute_instance" "vm" {
name = "demo-vm"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
provisioner "local-exec" {
command = <<EOT
curl -X POST -H 'Content-Type: application/json' \
-d '{"text":"VM 建立完成啦!(來自 Terraform)"}' \
"https://chat.googleapis.com/v1/spaces/AAA.../messages?key=xxx&token=yyy"
EOT
}
}
這樣 Terraform 在成功建立 VM 後,就會自動呼叫 Google Chat。
Provisioner 不只可以在「建立後」執行,還有其他情境:
lifecycle
,先建立新資源,再刪除舊的舉個例子:刪除 VM 前寄出警告信
provisioner "local-exec" {
when = destroy
command = "echo 'VM ${self.name} 即將被刪除' | mail -s '警告通知' admin@example.com"
}
很多人會拿它來「初始化 VM」裝軟體(例如安裝 Nginx),但這樣會讓 Terraform 的宣告式基礎架構變得太依賴命令式腳本,後續難以維護。
會比較建議用在:
還記得我們前面文章中有講過 Data Source 嗎?例如,查詢某個 GCP 區域有哪些可用的 Zone:
data "google_compute_zones" "available" {
region = "asia-east1"
}
output "zones" {
value = data.google_compute_zones.available.names
}
這樣 Terraform 就能動態抓到 asia-east1-a/b/c
而不是手動硬編碼。
但如果今天 Terraform 沒有內建的 Data Source 可以查呢?這時候就要用 External Data Source!它能讓 Terraform 執行一個外部程式(Python、Shell、Node.js…),並把輸出的 JSON 帶回來。
data "external" "app_version" {
program = ["python3", "${path.module}/scripts/get_version.py"]
}
output "version" {
value = data.external.app_version.result["version"]
}
scripts/get_version.py
#!/usr/bin/env python3
import json
print(json.dumps({"version": "1.2.3"}))
Terraform 會執行這支 Python,並把輸出的 JSON 存到 data.external.app_version.result
也很多人會用它來串接外部 API:
data "external" "apikey" {
program = ["bash", "${path.module}/scripts/fetch_key.sh"]
}
output "api_key" {
value = data.external.apikey.result["key"]
}
scripts/fetch_key.sh
#!/usr/bin/env bash
curl -s "https://example.com/get-key" | jq -c
這樣 Terraform 就能把外部 API 回傳的金鑰直接用在資源建立中。
特性 | Data Source(一般) | External Data Source |
---|---|---|
來源 | Provider 官方提供(AWS, GCP, Azure) | 任何外部程式(script / API) |
資料格式 | Provider 定義好 | 必須是 JSON |
適合場合 | 查詢雲端現有資源資訊 | Terraform 沒辦法直接取得的資訊 |
可以理解成:
今天認識了 Terraform 裡的兩個「外掛工具」:Provisioner 和 External Data Source。
前者適合在資源建立後做一些額外動作,例如發送通知;後者則能讓 Terraform 向外部程式或 API 查詢資訊,補足 Provider 沒支援的情境。
不過,這兩個工具都不適合當核心依賴。Provisioner 容易造成狀態不一致,External Data Source 也不該過度使用。最好的做法,是把它們當成輔助功能:需要時加上去,讓整個流程更靈活,但不要讓專案過度依賴。