Terraform 基础设施即代码:多云管理与自动化
Terraform 基础设施即代码实战教程
随着云原生和多云架构的普及,手动管理云资源已成为效率瓶颈。基础设施即代码(Infrastructure as Code, IaC)将基础设施的配置、编排和管理转化为可版本控制、可复用、可自动化的代码。在众多 IaC 工具中,Terraform 凭借其多云支持、声明式语法和强大的状态管理能力脱颖而出。本教程将带你从零开始,掌握使用 Terraform 进行多云管理和自动化的核心技能。
为什么选择 Terraform
Terraform 是 HashiCorp 开源的工具,使用 HCL(HashiCorp Configuration Language)定义基础设施。它的优势在于:
- 多云与混合云:支持 AWS、Azure、GCP、阿里云等数百个提供商,同一套语法管理不同云平台。
- 声明式配置:你描述目标状态,Terraform 自动计算和执行达到该状态所需的操作。
- 依赖解析:自动分析资源间依赖关系,按正确顺序创建或销毁。
- 状态管理:通过状态文件跟踪真实世界资源,支持远程后端协作。
- 模块化:可将可复用的基础设施封装为模块,像使用函数库一样分享。
环境准备与安装
在开始之前,请确保你的系统满足以下条件:
- 一个主流云平台的账号(本教程以 AWS 为例,基础操作对其他云适用)。
- 终端工具(macOS/Linux 终端,Windows 上推荐 PowerShell 或 WSL2)。
- 文本编辑器,如 VS Code(建议安装 Terraform 插件以获得语法高亮)。
安装 Terraform
- 前往 Terraform 官网下载页,选择对应操作系统的二进制包。
- 解压并将可执行文件
terraform放入系统 PATH 目录。- macOS/Linux 可使用
brew install terraform或直接移动文件到/usr/local/bin。 - Windows 可下载
.exe文件并配置环境变量。
- macOS/Linux 可使用
- 验证安装:
显示版本号即表示安装成功。terraform -version
AWS 凭证准备
使用 AWS 时,Terraform 需要有效的访问密钥。可通过环境变量或共享凭证文件配置。
方式一:环境变量
export AWS_ACCESS_KEY_ID=你的ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=你的SECRET_KEY
export AWS_DEFAULT_REGION=us-east-1
方式二:共享凭证文件
编辑 ~/.aws/credentials:
[default]
aws_access_key_id = 你的ACCESS_KEY
aws_secret_access_key = 你的SECRET_KEY
并设置 ~/.aws/config 中的默认区域:
[default]
region = us-east-1
核心概念速览
在编写配置之前,掌握几个关键术语能帮助你快速理解官方文档。
- Provider(提供商):与云平台、SaaS 服务等交互的插件。例如
aws、azurerm、google。需在配置中声明所需版本。 - Resource(资源):描述一个基础设施对象,如虚拟机、网络、DNS 记录等。它是配置中最基本的元素。
- Data Source(数据源):用于读取已经存在的外部信息,如获取 AMI ID、可用区信息等,不创建新资源。
- Module(模块):Terraform 配置的容器,用于封装一组关联资源,支持输入和输出变量,提升复用性。
- State(状态):记录 Terraform 管理的资源与实际基础设施映射关系的文件。默认本地存储,推荐团队使用远程后端(如 S3 + DynamoDB)。
- Provisioner(置备工具):在资源创建或销毁时执行脚本或配置管理工具(不推荐常规使用,应优先通过镜像或初始化脚本替代)。
第一个 Terraform 项目:部署 AWS EC2 实例
让我们从零构建一个项目,在 AWS 上启动一个可访问的 EC2 虚拟机。
-
新建项目目录并进入:
mkdir learn-terraform-aws cd learn-terraform-aws -
创建
main.tf文件,写入以下内容:terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = "us-east-1" } # 获取最新的 Amazon Linux 2 AMI data "aws_ami" "amzlinux" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } } # 创建一个安全组,允许 HTTP 和 SSH 访问 resource "aws_security_group" "web_sg" { name = "web-server-sg" description = "Allow HTTP and SSH inbound traffic" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] # 生产环境应限制为你的 IP } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } # 定义 EC2 实例 resource "aws_instance" "web" { ami = data.aws_ami.amzlinux.id instance_type = "t2.micro" key_name = "your-key-pair" # 替换为你的密钥对名称 vpc_security_group_ids = [aws_security_group.web_sg.id] user_data = <<-EOF #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Terraform</h1>" > /var/www/html/index.html EOF tags = { Name = "Terraform-Web" } } # 输出实例公网 IP output "instance_public_ip" { value = aws_instance.web.public_ip } -
代码说明:
terraform块声明了 Provider 的版本约束。provider "aws"配置 AWS 区域。data "aws_ami"动态查询 Amazon Linux 2 的 AMI ID,避免硬编码。resource "aws_security_group"定义安全组规则,开放 80 和 22 端口。resource "aws_instance"使用查询到的 AMI 和自定义的安全组,通过user_data脚本安装并启动 Apache Web 服务。output用于在部署完成后展示实例的公网 IP。
执行工作流:初始化、计划、应用
Terraform 的命令行工作流非常简洁,通常遵循三步:
-
初始化
在项目目录执行:terraform init该命令会下载 AWS Provider 插件,初始化后端和模块。
-
计划
在执行实际变更前,预览将要执行的操作:terraform planTerraform 会分析配置并与当前状态对比,输出增删改的详细清单。养成先
plan后apply的习惯,避免意外破坏。 -
应用
确认计划无误后,执行变更:terraform apply终端会再次显示计划,并提示输入
yes确认。执行成功后,你会看到输出的公网 IP。在浏览器中访问该 IP,即可看到 “Hello from Terraform” 页面。若要自动批准(适用于 CI/CD),可加
-auto-approve选项:terraform apply -auto-approve
管理状态与远程后端
本地状态文件 terraform.tfstate 保存了所有资源的映射信息。团队协作时,必须使用远程后端来共享状态并防止冲突。
使用 AWS S3 + DynamoDB 作为后端:
- 手动创建 S3 桶(如
my-terraform-state-bucket-unique)和 DynamoDB 表(如terraform-locks,主键为LockID,类型字符串)。 - 在
main.tf的terraform块中添加后端配置:terraform { backend "s3" { bucket = "my-terraform-state-bucket-unique" key = "prod/aws/ec2/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-locks" encrypt = true } } - 运行
terraform init重新初始化,Terraform 将把状态迁移到 S3。
使用远程后端后,多人协作时,每次 plan/apply 会自动获取锁,避免状态污染。
变量与输出:让配置更灵活
硬编码值会让配置难以复用。使用变量和输出文件分离敏感信息和环境差异。
定义变量(在 variables.tf 中):
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t2.micro"
}
variable "key_name" {
description = "SSH key pair name"
type = string
sensitive = true # 标记敏感,输出时隐藏
}
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}
引用变量(在 main.tf 中):
provider "aws" {
region = var.region
}
resource "aws_instance" "web" {
instance_type = var.instance_type
key_name = var.key_name
# ... 其他配置
}
提供变量值:可通过命令行传递、使用 terraform.tfvars 文件或环境变量。
# 命令行
terraform apply -var="key_name=my-key"
# 创建 terraform.tfvars
key_name = "my-key"
instance_type = "t3.micro"
输出定义(在 outputs.tf 中):
output "instance_id" {
value = aws_instance.web.id
}
output "public_dns" {
value = aws_instance.web.public_dns
}
执行 terraform output 可随时查看所有输出值。
模块化:构建可复用的基础设施组件
当项目复杂时,将可复用的模式封装为模块能极大提升效率。模块本质是包含 main.tf、variables.tf、outputs.tf 的子目录。
创建模块:
- 新建目录
modules/ec2-webserver,移入相关资源定义。 modules/ec2-webserver/variables.tf接收必要参数:variable "ami_id" {} variable "instance_type" {} variable "key_name" {} variable "subnet_id" {} variable "security_group_ids" { type = list(string) }- 在
modules/ec2-webserver/main.tf编写资源:resource "aws_instance" "this" { ami = var.ami_id instance_type = var.instance_type key_name = var.key_name subnet_id = var.subnet_id vpc_security_group_ids = var.security_group_ids # ... 通用 user_data 或标签等 } - 在
modules/ec2-webserver/outputs.tf中暴露需要的输出。
使用模块:
根目录 main.tf 调用模块:
module "web_server" {
source = "./modules/ec2-webserver"
ami_id = data.aws_ami.amzlinux.id
instance_type = var.instance_type
key_name = var.key_name
subnet_id = aws_subnet.main.id
security_group_ids = [aws_security_group.web_sg.id]
}
模块可以来自本地路径、Terraform Registry、Git 等,实现基础设施构建块的共享。
多环境管理(工作区与文件结构)
对于开发、测试、生产环境,推荐使用目录结构或 Terraform 工作区(Workspace)隔离配置。
目录结构法(适合环境差异大):
environments/
dev/
main.tf
terraform.tfvars
prod/
main.tf
terraform.tfvars
modules/
ec2-webserver/
...
每个环境目录独立执行 terraform init/apply,状态后端键值区分环境。
工作区法(适合差异小、用变量控制):
terraform workspace new dev
terraform workspace new prod
terraform workspace select dev
配合变量映射,在 main.tf 中根据 terraform.workspace 值选择不同配置。但需注意工作区不能改变后端配置,灵活性较低。
销毁资源与资源清理
不再需要资源时,彻底销毁所有 Terraform 管理的对象:
terraform destroy
Terraform 会生成销毁计划,确认后执行。该操作会删除 tfstate 中记录的每一个资源,请务必谨慎,尤其是生产环境。
单独移除某个资源可以从配置中删除该资源块并执行 apply,Terraform 将自动销毁对应真实资源。
最佳实践与进阶方向
- 代码审查与格式化:使用
terraform fmt统一代码风格;提交前执行terraform validate检查语法。 - 变量与敏感信息:永远不要将密钥、密码硬编码;使用环境变量、Hashicorp Vault 或云原生的密钥管理服务。
- 锁定 Provider 版本:在
required_providers中明确版本范围,避免破坏性升级。 - 远程状态锁定:团队环境务必配置 DynamoDB 或 Consul 等锁机制。
- 使用 Sentinel 或 OPA:实现策略即代码,强制合规性。
- 结合 CI/CD:在 GitHub Actions、GitLab CI 等流程中集成
terraform plan和apply,实现基础设施变更的自动化交付。
总结
通过本教程,你已掌握 Terraform 的基础工作流、状态管理、变量使用和模块化思想,并成功在 AWS 上部署了可访问的 Web 服务。Terraform 的强大在于其一致的声明式模型能够统一管理多云、混合云以及 SaaS 资源。继续探索官方 Registry 中的海量 Provider,实战中逐步深入网络规划、容器编排和合规策略,你将能够真正实现“基础设施即代码”带来的敏捷、可靠和可重复性。
现在是时候动手构建自己的项目了。打开终端,编写你的第一个 main.tf,让基础设施的创建变得像软件部署一样优雅。