iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0

昨天我們聊到 Dynamic Blocks,學會了怎麼在資源內部用迴圈展開子設定,減少重複、讓程式碼更乾淨。

今天我們要來看看 Functions(內建函數)和 Local Values(本地變數)。這兩個東西看似只是輔助工具,但在實務專案裡卻是讓 Terraform 程式碼 「好不好維護」的關鍵差異。

為什麼需要 Functions 與 Locals?

想像幾個常見場景:

  • 我們需要把一組 port [80, 443, 8080] 轉成字串,做為防火牆的名稱一部分。
  • 不同環境(dev、test、prod)的資源名稱必須加上後綴,否則會互相衝突。
  • 我們有一份 Map 設定,每個環境的值不同,要根據當下的環境自動取出正確的值。
  • 我們要過濾掉清單中某些元素,或取出其中幾個。

如果全部都硬寫在資源裡,不僅程式碼變醜,日後要改也很麻煩。
這時候,Functions 能幫我們處理「資料運算」,Locals 則能讓程式碼變「乾淨好讀」。

Functions:Terraform 內建小工具

Terraform 提供了上百個內建 Functions,涵蓋 字串、數字、布林、清單、Map、時間、雜湊 等操作。就像程式語言的標準函式庫一樣,能讓我們處理資料更靈活。

以下是一些常見的例子:

1. 字串處理

variable "env" {
  default = "prod"
}

output "name" {
  value = upper("${var.env}-app")   # => "PROD-APP"
}
  • upper() → 全部轉大寫
  • lower() → 全部轉小寫
  • replace("hello", "l", "x")"hexxo"

2. 清單處理

variable "ports" {
  default = [80, 443, 8080]
}

output "joined_ports" {
  value = join(",", var.ports)   # => "80,443,8080"

  • join() → 清單轉字串
  • split(",", "80,443,8080") → 還原成 ["80", "443", "8080"]
  • length(var.ports) → 取得長度(結果是 3)

3. Map 與 Lookup

variable "images" {
  default = {
    dev  = "nginx:1.18"
    prod = "nginx:1.24"
  }
}

output "prod_image" {
  value = lookup(var.images, "prod", "nginx:latest")

lookup() 會去 Map 裡找 key,如果找不到,就回傳預設值。
這樣就能避免 key 不存在時 Terraform 出錯。

4. 清單過濾與取值

variable "cidrs" {
  default = ["10.0.0.0/8", "192.168.0.0/16", "0.0.0.0/0"]
}

output "internal_cidrs" {
  value = slice(var.cidrs, 0, 2)   # => ["10.0.0.0/8", "192.168.0.0/16"]
}
  • slice(list, start, end) → 取子清單
  • contains(list, value) → 檢查是否存在
  • element(list, index) → 取出特定位置元素

這些小工具能幫我們省掉大量重複或硬編碼。

Local Values:乾淨的程式碼寫法

Functions 很好用,但如果你在一個資源裡面寫太多函數,程式碼就會變得很亂。
這時候就可以用 Local Values 來先計算,再引用。我們可以把 locals 想成中間變數:

範例:統一的命名規則

variable "env" {
  default = "prod"
}

locals {
  app_name = "${var.env}-app"
}

resource "google_storage_bucket" "example" {
  name     = local.app_name
  location = "US"
}

之後只要用 local.app_name 就好,不需要在每個地方重複拼接字串。

Locals 搭配 Functions

常見做法是先在 locals 裡,把複雜邏輯收斂起來,主程式碼就保持乾淨:

variable "ports" {
  default = [80, 443, 8080]
}

locals {
  firewall_name = "fw-${replace(join("-", var.ports), "8080", "custom")}"
}

output "result" {
  value = local.firewall_name   # => "fw-80-443-custom"
}

如果沒有 locals,這段邏輯就得直接塞在資源的 name 裡,讀起來非常混亂。

Functions vs Locals:對照表

特性 Functions Local Values
用途 處理資料(字串、清單、Map 等) 封裝計算結果,統一使用
範例 join(",", var.ports) local.app_name = "${var.env}-app"
適合場合 單純轉換、計算時 需要重複使用、程式碼過長時
優點 直接、快速、彈性 可讀性高、方便維護
缺點 太多函數會讓程式碼難讀 本身不做運算,還是需要 Functions 搭配

可以這樣理解:

  • Functions = 工具箱(隨時拿來處理資料)
  • Locals = 整理好的草稿紙(先算好,後面就不用重複)

Functions + Locals 實戰練習

假設我們要建立一台 VM,每個環境的名稱和硬碟大小都不同:

variable "env" {
  default = "dev"
}

locals {
  env_suffix = lower(var.env)
  disk_size  = var.env == "prod" ? 100 : 20
}

resource "google_compute_instance" "example" {
  name         = "app-${local.env_suffix}"
  machine_type = "e2-medium"

  boot_disk {
    initialize_params {
      size = local.disk_size
    }
  }
}
  • dev → VM 名稱:app-dev,磁碟:20GB
  • prod → VM 名稱:app-prod,磁碟:100GB

這就是 Functions + Locals 的威力:運算交給 Functions,維護交給 Locals

總結一下

今天我們學到:

  • Functions → Terraform 內建的小工具,可以靈活處理字串、清單、Map。
  • Local Values → 幫我們封裝計算結果,讓程式碼乾淨、可重複利用。
  • 對照表 → Functions 用來「算」,Locals 用來「收斂」。
  • 實戰應用 → 不同環境的命名與設定差異,都能用 Functions + Locals 解決。

這些技巧不會改變 Terraform 建立的資源數量,但會大幅提升 可讀性與可維護性,尤其是團隊合作時,大家都能快速理解程式碼的意圖。


上一篇
Day 21 - Terraform Dynamic Blocks 與複雜配置
系列文
30 天 Terraform 學習筆記:從零開始的 IaC 實戰22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言