CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Terraform 基础设施即代码/课时/变量与输出
RawBlame
课时目录12 节

Terraform 基础设施即代码

  1. 01Terraform 是什么
  2. 02HCL 语法
  3. 03init 与 Provider
  4. 04plan 与 apply
  5. 05State 管理
  6. 06变量与输出
  7. 07Module 复用
  8. 08AWS 资源示例
  9. 09Terraform 与 K8s
  10. 10CI 中的 Terraform
  11. 11Terraform vs Helm
  12. 12综合练习

变量与输出

variable、output、tfvars 分环境。

30 分钟

变量、输出与 tfvars

这一课你将能做到

  1. 用 variable 块声明带类型、默认值、校验规则的输入变量,并区分四种赋值方式的优先级
  2. 用 output 块输出 IP、地址等结果,理解敏感输出的处理
  3. 用 dev/prod 两套 tfvars 文件让同一份配置跑出不同环境

为什么要学

没有变量,你的 Terraform 配置只能服务一个环境:实例类型写死、环境名写死、密码写死。真实项目至少有开发、测试、生产三套,它们结构相同、参数不同。变量 + tfvars 就是 Terraform 的「参数化」机制,和 Java 方法入参是一个道理;输出则是把创建结果「return」出来,给人和其他系统看。CI 流水线里换环境,本质就是换一个 tfvars 文件。

人话:配置是菜谱,变量是「微辣还是特辣、加不加香菜」的勾选单,tfvars 就是事先填好的两种套餐;output 是菜做好后服务员告诉你的取餐号。

先建立图像

变量赋值的四种方式(优先级从低到高):

1. variable 块里的 default(最低)
2. terraform.tfvars / *.auto.tfvars 文件
3. -var-file 指定的文件、-var 单独传入
4. 环境变量 TF_VAR_xxx(与 -var 同级,按具体规则覆盖)

核心心智模型:

概念Java 类比作用
variable方法参数调用方传值进来
locals方法内局部变量配置内部计算复用
outputreturn 值把结果暴露出去

跟着做

步骤 1:声明带类型和默认值的变量

新建 vars-demo/variables.tf:

variable "project" {
  description = "项目名,用于资源命名和标签"
  type        = string
  default     = "springboot-demo"
}

variable "instance_type" {
  description = "EC2 实例规格"
  type        = string
  default     = "t3.micro"
}

variable "env" {
  description = "环境标识:dev/staging/prod"
  type        = string
}

variable "allowed_ports" {
  description = "安全组放行的端口列表"
  type        = list(number)
  default     = [22, 8080]
}

没有 default 的变量(env)必须在 plan/apply 时提供,否则 Terraform 会交互式询问。

步骤 2:加校验规则

variable "env" {
  description = "环境标识"
  type        = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.env)
    error_message = "env 只能是 dev、staging、prod 之一。"
  }
}

validation 在加载阶段执行,传入 test 会直接拒绝,连 plan 都进不去。这比把错误拖到云 API 报回来说清楚得多。

步骤 3:在配置中使用

main.tf:

terraform {
  required_version = ">= 1.7.0"
}

resource "null_resource" "app" {
  triggers = {
    project      = var.project
    instance     = var.instance_type
    env          = var.env
    port_count   = length(var.allowed_ports)
    first_port   = var.allowed_ports[0]
  }
}

步骤 4:用 tfvars 文件区分环境

新建 dev.tfvars:

env           = "dev"
instance_type = "t3.micro"
allowed_ports = [22, 8080]

新建 prod.tfvars:

env           = "prod"
instance_type = "t3.small"
allowed_ports = [8080]

注意:生产 tfvars 只放非敏感参数,密码绝不写这里(见步骤 7)。

分别执行:

terraform plan -var-file=dev.tfvars
terraform plan -var-file=prod.tfvars

对比两次计划的差异——同一份配置,两套参数。文件名固定为 terraform.tfvars 时会自动加载,省去 -var-file。

步骤 5:输出结果

新建 outputs.tf:

output "project_full_name" {
  description = "环境与项目组合名"
  value       = "${var.env}-${var.project}"
}

output "instance_type" {
  value = var.instance_type
}

apply 后终端会打印输出;不想每次 apply 都刷一屏,可用:

terraform output
terraform output instance_type

步骤 6:敏感变量与敏感输出

模拟数据库密码:

variable "db_password" {
  description = "RDS 管理员密码"
  type        = string
  sensitive   = true
}

output "db_password_echo" {
  value     = var.db_password
  sensitive = true
}

sensitive = true 的变量和输出不会显示在终端和日志里(显示为 sensitive)。但要清醒:它仍然明文存在于 state 文件中,sensitive 只防「屏幕肩窥」,不防 state 泄露。

步骤 7:用环境变量传密钥(不落盘)

$env:TF_VAR_db_password = "你的强密码"
terraform plan -var-file=prod.tfvars

Terraform 自动把 TF_VAR_ 前缀的环境变量绑定到同名变量。CI 的密钥管理(GitHub Secrets、GitLab CI variables)都走这条路,密码不进任何文件。

步骤 8:复杂类型变量

variable "apps" {
  type = map(object({
    port = number
    size = string
  }))
  default = {
    order = { port = 8080, size = "t3.micro" }
    pay   = { port = 8081, size = "t3.small" }
  }
}

output "app_ports" {
  value = { for k, v in var.apps : k => v.port }
}

object/list/map 可以自由组合,1.3+ 还支持 optional() 标记对象内可选字段,配置模块接口时很好用。

讲清楚要点

  1. 变量只定义在一个地方:variables.tf 声明,tfvars 赋值,资源中引用,三处各司其职,别在资源块里复制默认值。
  2. tfvars 也建议进 Git(非敏感的):环境参数是配置的一部分,评审有价值;敏感值走环境变量或 Secrets Manager。
  3. output 依赖资源属性时只在 apply 后有值:plan 阶段会显示 <sensitive> 或 known after apply,属正常。
  4. -var 适合临时覆盖单个值:如 terraform apply -var="instance_type=t3.medium",但临时改动容易忘,团队流程里应留下记录。
  5. 变量类型要写:不写类型默认 any,调用方传错形状要到很深层才报错;显式 string/number/bool/集合类型把错误挡在门口。

你可能会懵的地方

  • 改了 tfvars 为什么 plan 没变化? 文件名不是 terraform.tfvars 又没加 -var-file,Terraform 不会自动加载任意命名文件。确认加载方式。

  • 变量和 locals 到底选哪个? 需要调用方按环境改变的用 variable;只是配置内部避免重复、做派生计算的用 locals。locals 外部无法传值。

  • sensitive 了为什么 state 里还能看到? sensitive 是 UI 层脱敏,state 需要真实值来管理资源。保护 state 存储(加密、桶权限)才是根本。

  • 能在变量之间引用吗,比如 var.b 默认值引用 var.a? 不能。变量默认值必须是字面常量。需要联动就定义 locals 做派生。

  • tfvars 和 .auto.tfvars 有什么区别? terraform.tfvars 和 *.auto.tfvars 自动加载,后者可以多文件并存(按字母序);其余命名必须显式 -var-file。

错法对照

错法问题正解
密码写进 prod.tfvars 提交 Git凭据泄露TF_VAR_ 环境变量或密钥服务
不写 type,全靠默认 any传错类型晚报错显式声明类型
资源里到处写默认值字符串改环境时漏改一律走 var.xxx
output 打印完整密码还不标 sensitive日志泄露sensitive = true,最好不输出密钥
本地直接改 state 里的值当「改变量」状态与配置分裂改变量和配置,重新 apply

卡点急救

  1. No value for required variable:变量无 default 且未传值。加 -var-file、-var 或 TF_VAR_ 环境变量。
  2. validation 报错但不知传了啥:检查命令行顺序和自动加载的 tfvars;terraform console 输入 var.env 可查看当前解析值。
  3. tfvars 中文或路径问题:文件保存为 UTF-8;路径含空格时 -var-file="my vars/dev.tfvars" 加引号。

面试常问

  • Terraform 变量有哪几种赋值方式?优先级如何? default 默认值最低;自动加载的 terraform.tfvars / *.auto.tfvars;-var-file 与 -var;TF_VAR_ 环境变量(命令行参数优先级最高)。同名变量以后加载/高优先级者为准。

  • sensitive = true 能防止密码泄露吗? 只能防止输出到终端和日志;state 文件中仍为明文。需要同时严格限制 state 存储访问,或让资源直接从 Secrets Manager/KMS 取密钥。

  • dev/prod 共用一份配置如何实现? 配置只引用变量,每环境一份 tfvars(规格、副本、白名单不同),CI 按环境选择 -var-file;敏感值走环境变量注入。

自测三问

  1. 执行 plan 时不想交互输入,让 env=dev 自动生效,有哪几种做法?
  2. 为什么不建议把数据库密码写进 tfvars 文件?sensitive 能解决这个问题吗?
  3. variable、locals、output 分别在什么时机用?

小结一句话

变量负责把「环境差异」从配置里抽出来,tfvars 按环境填值、环境变量传密钥,output 回传结果,sensitive 只管屏幕不管 state。

延伸

  • Input Variables 输入变量
  • Output Values 输出值
  • Variable Definition Files tfvars 规则
  • 下一课:Module 模块复用——像搭积木一样组合基础设施。
加载本节练习…
← 上一课State 管理下一课 →Module 复用