Terraform 是当下最主流的基础设施即代码(IaC)工具:你不再手动在云控制台点选 ECS、安全组、数据库,而是用一份 HCL 文件声明“最终要长什么样”,由 Terraform 计算出变更并安全地落地。本文从 provider、resource 讲到 state 状态管理与 module 模块化,并带你用阿里云实操一套可复用的基础设施模板,把“点出来的环境”变成“版本控制里的基础设施”。
一、Terraform 是什么:为什么用代码管基础设施
传统运维靠手点控制台,环境一旦复杂就面临“配置漂移”——测试环境和生产环境慢慢对不上,出问题时没人说得清到底改了哪。Terraform 把基础设施抽象成代码,每一次变更都可评审、可回滚、可复制。
1.1 声明式 vs 命令式
命令式告诉你“先做什么再做什么”(比如一串 shell 脚本),声明式只描述“目标状态”。Terraform 属于后者:你写“我要一台 2 核 4G 的 ECS”,它自己决定是新建、还是改配置、还是什么都不做。
1.2 核心工作模型
三个关键概念贯穿全文:Provider 是云厂商插件(阿里云、AWS、腾讯云);Resource 是一个具体资源(一台实例、一个_bucket);State 是 Terraform 记录“现实长什么样”的本地/远程快照,用来比对目标与现状的差值。
二、快速上手:写第一个 main.tf
一个最小可运行的 Terraform 配置通常包含 provider 块与若干 resource 块。下面用阿里云为例,声明一台 ECS 实例。
2.1 provider 与 resource
# main.tf
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.220"
}
}
}
provider "alicloud" {
region = "cn-hangzhou"
}
resource "alicloud_instance" "web" {
instance_name = "tf-demo-web"
instance_type = "ecs.c7.large" # 2 vCPU / 4 GiB
image_id = "ubuntu_22_04_x64_20G_alibase_20240101.vhd"
security_groups = [alicloud_security_group.web.id]
vswitch_id = "vsw-bp1xxxxxx"
internet_max_bandwidth_out = 10
}
写好配置后,标准三步把环境拉起来。注意 plan 会预览变更而不真正执行,上线前务必先看 diff。
2.2 init / plan / apply
# 1. 下载 provider 插件(首次或改 provider 时)
terraform init
# 2. 预览变更:+ 新建 / - 删除 / ~ 修改
terraform plan
# 3. 真正执行(交互确认);非交互用 -auto-approve
terraform apply
# 销毁整套环境(危险,慎用)
terraform destroy
三、状态管理 state:Terraform 的“记忆”
很多人初学踩的第一个坑就是 state。State 文件记录了资源与云上实体的映射,一旦丢失或多人各持一份,Terraform 就会以为资源不存在而重复创建,或误删线上资产。
3.1 本地 state 的三个坑
默认 terraform.tfstate 落在本地:① 团队协作时互相覆盖;② 文件进了 Git 可能泄露密钥;③ 本地机器坏了状态就没了。所以生产环境一定用远程后端。
3.2 远程后端实战(阿里云 OSS)
# backend.tf
terraform {
backend "oss" {
bucket = "my-tf-state"
key = "prod/web/terraform.tfstate"
region = "cn-hangzhou"
# 建议同时开启 OSS 版本控制与合规保留,防误删
}
}
迁移到远程后端只需再跑一次 terraform init,它会提示把本地 state 迁过去。远程后端天然支持状态锁,避免两个人同时 apply 互相冲掉。
四、变量与模块化:写出可复用的基础设施
硬编码配置没法复用。用 variable 抽参数、output 暴露结果,再用 module 把一组资源打包成“积木”,就能一份代码管多套环境。
4.1 variable 与 output
# variables.tf
variable "instance_type" {
type = string
default = "ecs.c7.large"
description = "ECS 规格"
}
# outputs.tf
output "web_public_ip" {
value = alicloud_instance.web.public_ip
}
4.2 module 复用
# 主配置里调用自定义模块
module "web_cluster" {
source = "./modules/web"
instance_type = var.instance_type
replica = 2
}
常见变量类型与默认值策略如下,合理设默认值能降低调用方的心智负担。
| 类型 | 示例 | 适用场景 |
| string | “ecs.c7.large” | 规格、地域、镜像 ID |
| number | 2 | 副本数、带宽 |
| list(string) | [“sg-a”,”sg-b”] | 安全组列表、可用区 |
| map(any) | {env=”prod”} | 标签、环境变量 |
五、生产实战:用代码拉起一套 Web 服务
下面把前面知识点串起来:声明安全组、ECS,并自动输出公网 IP。这与手动在控制台操作等价,但全程可评审、可复制。
5.1 安全组 + ECS 联动
resource "alicloud_security_group" "web" {
name = "tf-web-sg"
vpc_id = "vpc-bp1xxxxxx"
}
resource "alicloud_security_group_rule" "ssh" {
type = "ingress"
ip_protocol = "tcp"
port_range = "22/22"
security_group_id = alicloud_security_group.web.id
cidr_ip = "10.0.0.0/8" # 仅内网,避免 0.0.0.0/0 暴露
}
安全组规则建议只放行必要端口、来源尽量收紧。服务器层面的加固可参考我们的服务器安全加固:SSH / 防火墙 / Fail2ban 实战指南,把“网络入口”和“主机防护”两道防线都立起来。
六、踩坑与最佳实践
6.1 新手最常踩的雷区
① 把 .tfstate 提交到 Git;② 在资源已存在时又写一遍导致冲突(应先用 terraform import 接管存量资源);③ 对生产环境直接 apply -auto-approve 不看 plan;④ 用 count 改列表顺序导致资源被整体重建。
| 命令 | 作用 | 上线前必做 |
| terraform fmt | 格式化代码 | 建议 CI 校验 |
| terraform validate | 语法/类型校验 | 必做 |
| terraform plan | 预览变更 | 必做,存为产物 |
| terraform apply | 落地变更 | 看 plan 后再执行 |
6.2 把 Terraform 接进 CI/CD
把 fmt + validate + plan 放进入库流水线是低成本高回报的护栏。我们的K8s 入门:Pod、Deployment、Service与Docker 网络模式详解都强调“环境一致性”,而 Terraform 正是把这份一致性从容器层一路管到云资源层的关键一环。
七、与现有运维体系衔接
Terraform 负责“建”,建好之后的“跑”和“存”另有专人:用K8s 持久化存储 PV/PVC承载有状态负载,用服务器安全加固守住主机边界。IaC 不是银弹,但它是让整套环境“可声明、可复现、可审计”的地基——当你能在 10 分钟内用一份代码重建整套预发环境时,就会再也回不去手动点控制台的日子。
总结
Terraform 把基础设施变成了和应用程序一样的代码:声明目标、预览变更、安全落地、远程锁状态、模块化复用。掌握 provider / resource / state / module 这四块,你就能用一套 HCL 管起跨云、跨环境的所有资源,让“环境即代码”真正落地。




