在 Terraform 中,變數(Variables)與輸出值(Outputs)是建構可重用、可維護基礎設施程式碼的關鍵元素。本文將深入探討變數的各種類型、定義方式、驗證機制、敏感資料處理,以及輸出值的進階設定。
變數類型(Variable Types)
Terraform 支援多種變數類型,大致可分為基本型別(Primitive Types)和複雜型別(Complex Types)。
基本型別
| 型別 | 說明 | 範例 |
|---|
string | 一組 Unicode 字元組成的文字 | "Hello, World" |
number | 數值,可以是整數或浮點數 | 15, 6.283185 |
bool | 布林值 | true, false |
複雜型別
| 型別 | 說明 | 範例 |
|---|
list | 有序的值序列 | ["a", "b", "c"] |
set | 無序且唯一的值集合 | toset(["a", "b", "c"]) |
map | 鍵值對的集合 | {name = "John", age = 30} |
object | 具有命名屬性的結構化資料 | object({name = string, age = number}) |
tuple | 固定長度、可包含不同型別的序列 | tuple([string, number, bool]) |
變數定義方式
基本變數定義
在 Terraform 中,使用 variable 區塊來定義變數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| variable "instance_type" {
description = "EC2 執行個體類型"
type = string
default = "t3.micro"
}
variable "instance_count" {
description = "要建立的執行個體數量"
type = number
default = 1
}
variable "enable_monitoring" {
description = "是否啟用監控"
type = bool
default = true
}
|
複雜型別變數定義
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # List 型別
variable "availability_zones" {
description = "可用區域清單"
type = list(string)
default = ["ap-northeast-1a", "ap-northeast-1c"]
}
# Map 型別
variable "instance_tags" {
description = "執行個體標籤"
type = map(string)
default = {
Environment = "production"
Project = "web-app"
}
}
# Object 型別
variable "database_config" {
description = "資料庫設定"
type = object({
engine = string
engine_version = string
instance_class = string
storage_size = number
multi_az = bool
})
default = {
engine = "mysql"
engine_version = "8.0"
instance_class = "db.t3.medium"
storage_size = 100
multi_az = true
}
}
|
變數賦值方式
Terraform 提供多種方式來為變數賦值:
1. 命令列參數
1
| terraform apply -var="instance_type=t3.large"
|
1
2
3
4
| # terraform.tfvars
instance_type = "t3.large"
instance_count = 3
enable_monitoring = true
|
3. 環境變數
1
2
| export TF_VAR_instance_type="t3.large"
terraform apply
|
4. 自動載入的變數檔案
Terraform 會自動載入以下檔案:
terraform.tfvarsterraform.tfvars.json*.auto.tfvars*.auto.tfvars.json
變數驗證(Variable Validation)
Terraform 提供變數驗證機制,可在 plan 或 apply 階段檢查輸入值是否符合預期規則。
基本驗證
1
2
3
4
5
6
7
8
9
| variable "instance_type" {
description = "EC2 執行個體類型"
type = string
validation {
condition = can(regex("^t[23]\\.", var.instance_type))
error_message = "執行個體類型必須為 t2 或 t3 系列"
}
}
|
多重驗證規則
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| variable "database_port" {
description = "資料庫連接埠"
type = number
validation {
condition = var.database_port >= 1024 && var.database_port <= 65535
error_message = "連接埠必須介於 1024 到 65535 之間"
}
validation {
condition = var.database_port != 3389
error_message = "不可使用 RDP 連接埠 3389"
}
}
|
複雜型別驗證
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| variable "vpc_config" {
description = "VPC 設定"
type = object({
cidr_block = string
subnets = list(string)
})
validation {
condition = can(cidrhost(var.vpc_config.cidr_block, 0))
error_message = "CIDR 區塊格式不正確"
}
validation {
condition = length(var.vpc_config.subnets) >= 2
error_message = "至少需要定義 2 個子網路"
}
}
|
敏感變數處理(Sensitive Variables)
對於 API 金鑰、密碼等敏感資料,Terraform 提供 sensitive 參數來保護這些值不會在 CLI 輸出中顯示。
定義敏感變數
1
2
3
4
5
6
7
8
9
10
11
| variable "db_password" {
description = "資料庫密碼"
type = string
sensitive = true
}
variable "api_key" {
description = "API 金鑰"
type = string
sensitive = true
}
|
使用敏感變數
1
2
3
4
5
6
7
8
9
| resource "aws_db_instance" "main" {
identifier = "production-db"
engine = "mysql"
engine_version = "8.0"
instance_class = "db.t3.medium"
username = "admin"
password = var.db_password # 敏感值不會顯示在 plan 輸出中
}
|
重要提醒:雖然 sensitive = true 可以防止值在 CLI 輸出中顯示,但這些值仍會以明文形式儲存在 Terraform 狀態檔案(state file)中。請務必妥善保護您的狀態檔案存取權限。
敏感資料最佳實踐
- 使用外部秘密管理工具:如 HashiCorp Vault、AWS Secrets Manager
- 加密狀態檔案:使用遠端後端(如 S3)並啟用加密
- 限制狀態檔案存取:透過 IAM 政策控制誰可以讀取狀態
1
2
3
4
5
6
7
8
| # 使用 AWS Secrets Manager 取得敏感資料
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "production/database/password"
}
resource "aws_db_instance" "main" {
password = data.aws_secretsmanager_secret_version.db_password.secret_string
}
|
輸出值設定(Output Values)
輸出值用於將模組內部的資訊暴露給外部使用,是模組間共享資料的重要機制。
基本輸出值
1
2
3
4
5
6
7
8
9
| output "instance_id" {
description = "EC2 執行個體 ID"
value = aws_instance.main.id
}
output "instance_public_ip" {
description = "EC2 執行個體公開 IP"
value = aws_instance.main.public_ip
}
|
敏感輸出值
1
2
3
4
5
| output "db_connection_string" {
description = "資料庫連線字串"
value = "mysql://${aws_db_instance.main.username}:${aws_db_instance.main.password}@${aws_db_instance.main.endpoint}"
sensitive = true
}
|
使用 depends_on
在某些情況下,您可能需要明確指定輸出值的依賴關係:
1
2
3
4
5
| output "web_endpoint" {
description = "網站端點 URL"
value = "https://${aws_instance.web.public_dns}"
depends_on = [aws_security_group.web_sg]
}
|
這在以下情況特別有用:
- 確保安全群組規則已套用後才輸出連線資訊
- 等待特定資源完全就緒後才暴露端點
輸出值條件判斷
1
2
3
4
| output "load_balancer_dns" {
description = "負載平衡器 DNS 名稱"
value = var.enable_load_balancer ? aws_lb.main[0].dns_name : null
}
|
複雜輸出值
1
2
3
4
5
6
7
8
9
10
11
| output "instance_details" {
description = "所有執行個體的詳細資訊"
value = {
for instance in aws_instance.main :
instance.tags["Name"] => {
id = instance.id
private_ip = instance.private_ip
public_ip = instance.public_ip
}
}
}
|
實際應用範例
以下是一個完整的模組範例,展示變數與輸出值的綜合運用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| # variables.tf
variable "environment" {
description = "部署環境名稱"
type = string
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "環境必須為 dev、staging 或 production"
}
}
variable "app_config" {
description = "應用程式設定"
type = object({
name = string
port = number
replicas = number
container_image = string
})
validation {
condition = var.app_config.port >= 1 && var.app_config.port <= 65535
error_message = "連接埠必須在有效範圍內"
}
validation {
condition = var.app_config.replicas >= 1
error_message = "至少需要 1 個副本"
}
}
variable "secrets" {
description = "應用程式秘密資訊"
type = object({
db_password = string
api_key = string
})
sensitive = true
}
# outputs.tf
output "application_url" {
description = "應用程式存取 URL"
value = "https://${aws_lb.app.dns_name}:${var.app_config.port}"
}
output "deployment_info" {
description = "部署資訊摘要"
value = {
environment = var.environment
app_name = var.app_config.name
replicas = var.app_config.replicas
created_at = timestamp()
}
}
|
總結
善用 Terraform 的變數與輸出值功能,可以讓您的基礎設施程式碼更加:
- 可重用:透過變數參數化設定
- 安全:使用敏感變數保護機密資料
- 可靠:透過變數驗證確保輸入值正確
- 模組化:透過輸出值實現模組間的資料共享
掌握這些進階技巧,將有助於您建構更專業、更易維護的 Terraform 專案。
參考資源