跳转到内容

Terraform 基础

Terraform 是 HashiCorp 开发的基础设施即代码(Infrastructure as Code, IaC)工具,使用声明式配置语言 HCL(HashiCorp Configuration Language)来定义和管理云资源。通过 Terraform,你可以用代码描述完整的基础设施架构,实现版本控制和可重复部署。

通过官方仓库安装(EL 9 / EL 10)
# 安装 DNF 插件(提供 config-manager)
sudo dnf install -y dnf-plugins-core
# 添加 HashiCorp 官方仓库
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
# 安装 Terraform
sudo dnf install -y terraform
# 验证安装
terraform version
Terminal window
# 下载最新版本(访问 https://developer.hashicorp.com/terraform/install 确认最新版本号)
TERRAFORM_VERSION="1.9.0" # 示例版本,请替换为官网最新版本号
wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip
# 解压并安装
sudo dnf install -y unzip
unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip
sudo mv terraform /usr/local/bin/
sudo chmod +x /usr/local/bin/terraform
# 验证
terraform version
Terminal window
# 安装自动补全
terraform -install-autocomplete
# 重新加载 shell
source ~/.bashrc

Terraform 配置文件使用 .tf 扩展名,采用 HCL 语法。

# 注释以 # 开头
# 块(Block)结构
resource "类型" "名称" {
参数1 = "值1"
参数2 = 123
# 嵌套块
nested_block {
key = "value"
}
}
# 字符串插值
variable "name" {
default = "myserver"
}
resource "example" "demo" {
name = "prefix-${var.name}"
}
# 字符串
name = "web-server"
# 数字
count = 3
# 布尔值
enabled = true
# 列表
availability_zones = ["cn-hangzhou-a", "cn-hangzhou-b"]
# 映射(Map)
tags = {
Name = "web-server"
Environment = "production"
Team = "ops"
}

Provider 是 Terraform 与云平台交互的插件。

providers.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1" # 东京区域
access_key = var.aws_access_key
secret_key = var.aws_secret_key
# 或者使用环境变量(推荐):
# export AWS_ACCESS_KEY_ID="your-access-key"
# export AWS_SECRET_ACCESS_KEY="your-secret-key"
}
providers.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.220"
}
}
}
provider "alicloud" {
region = "cn-hangzhou"
access_key = var.alicloud_access_key
secret_key = var.alicloud_secret_key
}
# variables.tf - 变量定义
variable "aws_access_key" {
description = "AWS Access Key"
type = string
sensitive = true
}
variable "aws_secret_key" {
description = "AWS Secret Key"
type = string
sensitive = true
}
variable "instance_type" {
description = "EC2 实例类型"
type = string
default = "t3.micro"
}
variable "instance_count" {
description = "实例数量"
type = number
default = 1
}
# main.tf - 主配置文件
# 查询最新的 AlmaLinux 9 AMI
data "aws_ami" "almalinux9" {
most_recent = true
owners = ["764336703387"] # AlmaLinux 官方
filter {
name = "name"
values = ["AlmaLinux OS 9*x86_64*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# 创建安全组
resource "aws_security_group" "web" {
name = "web-sg"
description = "Allow HTTP and SSH"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "SSH"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP"
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "web-security-group"
}
}
# 创建 EC2 实例
resource "aws_instance" "web" {
count = var.instance_count
ami = data.aws_ami.almalinux9.id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
echo "<h1>Server ${count.index + 1}</h1>" > /usr/share/nginx/html/index.html
EOF
tags = {
Name = "web-server-${count.index + 1}"
Env = "production"
}
}
# outputs.tf - 输出定义
output "instance_public_ips" {
description = "实例公网 IP 列表"
value = aws_instance.web[*].public_ip
}
output "instance_ids" {
description = "实例 ID 列表"
value = aws_instance.web[*].id
}
output "ami_id" {
description = "使用的 AMI ID"
value = data.aws_ami.almalinux9.id
}
# main.tf - 阿里云 ECS 示例
variable "alicloud_access_key" {
type = string
sensitive = true
}
variable "alicloud_secret_key" {
type = string
sensitive = true
}
# 查询可用区
data "alicloud_zones" "default" {
available_resource_creation = "VSwitch"
}
# 查询镜像
data "alicloud_images" "almalinux" {
name_regex = "^almalinux_9"
most_recent = true
owners = "system"
}
# 创建 VPC
resource "alicloud_vpc" "main" {
vpc_name = "tf-demo-vpc"
cidr_block = "172.16.0.0/16"
}
# 创建交换机
resource "alicloud_vswitch" "main" {
vswitch_name = "tf-demo-vsw"
vpc_id = alicloud_vpc.main.id
cidr_block = "172.16.1.0/24"
zone_id = data.alicloud_zones.default.zones[0].id
}
# 创建安全组
resource "alicloud_security_group" "web" {
name = "tf-demo-sg"
vpc_id = alicloud_vpc.main.id
}
resource "alicloud_security_group_rule" "allow_ssh" {
type = "ingress"
ip_protocol = "tcp"
port_range = "22/22"
security_group_id = alicloud_security_group.web.id
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "allow_http" {
type = "ingress"
ip_protocol = "tcp"
port_range = "80/80"
security_group_id = alicloud_security_group.web.id
cidr_ip = "0.0.0.0/0"
}
# 创建 ECS 实例
resource "alicloud_instance" "web" {
instance_name = "tf-demo-ecs"
image_id = data.alicloud_images.almalinux.images[0].id
instance_type = "ecs.t6-c1m1.large"
security_groups = [alicloud_security_group.web.id]
vswitch_id = alicloud_vswitch.main.id
internet_max_bandwidth_out = 10
system_disk_size = 40
user_data = base64encode(<<-EOF
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
EOF
)
tags = {
Name = "web-server"
Env = "demo"
}
}
output "public_ip" {
value = alicloud_instance.web.public_ip
}
Terminal window
# 进入项目目录
cd /opt/terraform/myproject
# 初始化(下载 Provider 插件)
terraform init
# 升级 Provider 版本
terraform init -upgrade
Terminal window
# 查看计划(预览将要执行的变更)
terraform plan
# 将计划保存到文件
terraform plan -out=tfplan
# 使用变量文件
terraform plan -var-file="production.tfvars"
# 传递单个变量
terraform plan -var="instance_count=3"
Terminal window
# 应用变更(会要求确认)
terraform apply
# 使用保存的计划文件(无需确认)
terraform apply tfplan
# 自动确认(用于 CI/CD)
terraform apply -auto-approve
# 使用变量文件
terraform apply -var-file="production.tfvars"
Terminal window
# 销毁所有资源
terraform destroy
# 自动确认销毁
terraform destroy -auto-approve
# 仅销毁指定资源
terraform destroy -target=aws_instance.web
Terminal window
# 格式化配置文件
terraform fmt
# 递归格式化
terraform fmt -recursive
# 验证配置语法
terraform validate
# 查看当前状态
terraform show
# 列出所有资源
terraform state list
# 查看特定资源的详细信息
terraform state show aws_instance.web[0]
# 刷新状态(同步远端实际状态)
terraform refresh
# 生成依赖关系图
terraform graph | dot -Tpng > graph.png

使用 .tfvars 文件管理不同环境的变量:

production.tfvars
instance_type = "t3.large"
instance_count = 3
staging.tfvars
instance_type = "t3.micro"
instance_count = 1
Terminal window
# 使用不同环境的变量
terraform apply -var-file="production.tfvars"
terraform apply -var-file="staging.tfvars"

通过环境变量传递敏感信息:

Terminal window
# Terraform 会自动读取 TF_VAR_ 前缀的环境变量
export TF_VAR_aws_access_key="AKIAIOSFODNN7EXAMPLE"
export TF_VAR_aws_secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
terraform apply

Terraform 状态文件(terraform.tfstate)记录了基础设施的当前状态。在团队协作中,应使用远程后端存储状态文件。

Terminal window
# 状态文件位于项目目录
ls -la terraform.tfstate
ls -la terraform.tfstate.backup
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-lock" # 状态锁定
}
}
terraform {
backend "oss" {
bucket = "my-terraform-state"
prefix = "production"
region = "cn-hangzhou"
encrypt = true
tablestore_endpoint = "https://tf-state-lock.cn-hangzhou.ots.aliyuncs.com"
tablestore_table = "terraform-lock"
}
}
Terminal window
# 列出状态中的资源
terraform state list
# 查看资源详情
terraform state show aws_instance.web[0]
# 移动资源(重命名)
terraform state mv aws_instance.web aws_instance.webserver
# 从状态中移除资源(不删除实际资源)
terraform state rm aws_instance.web[0]
# 导入已有资源到 Terraform 管理
terraform import aws_instance.web i-0abc123def456
# 拉取远程状态
terraform state pull > state.json
# 推送状态到远端
terraform state push state.json

模块(Module)用于封装和复用 Terraform 配置。

Terminal window
# 模块目录结构
mkdir -p modules/ecs-instance
modules/ecs-instance/variables.tf
variable "instance_name" {
description = "实例名称"
type = string
}
variable "instance_type" {
description = "实例规格"
type = string
default = "ecs.t6-c1m1.large"
}
variable "image_id" {
description = "镜像 ID"
type = string
}
variable "vswitch_id" {
description = "交换机 ID"
type = string
}
variable "security_group_id" {
description = "安全组 ID"
type = string
}
variable "tags" {
description = "资源标签"
type = map(string)
default = {}
}
modules/ecs-instance/main.tf
resource "alicloud_instance" "this" {
instance_name = var.instance_name
instance_type = var.instance_type
image_id = var.image_id
vswitch_id = var.vswitch_id
security_groups = [var.security_group_id]
internet_max_bandwidth_out = 10
system_disk_size = 40
tags = var.tags
}
modules/ecs-instance/outputs.tf
output "instance_id" {
value = alicloud_instance.this.id
}
output "public_ip" {
value = alicloud_instance.this.public_ip
}
output "private_ip" {
value = alicloud_instance.this.private_ip
}
# main.tf - 使用自定义模块
module "web_server" {
source = "./modules/ecs-instance"
instance_name = "web-server-01"
instance_type = "ecs.t6-c1m1.large"
image_id = data.alicloud_images.almalinux.images[0].id
vswitch_id = alicloud_vswitch.main.id
security_group_id = alicloud_security_group.web.id
tags = {
Role = "web"
Env = "production"
}
}
module "api_server" {
source = "./modules/ecs-instance"
instance_name = "api-server-01"
instance_type = "ecs.c6.large"
image_id = data.alicloud_images.almalinux.images[0].id
vswitch_id = alicloud_vswitch.main.id
security_group_id = alicloud_security_group.web.id
tags = {
Role = "api"
Env = "production"
}
}
output "web_server_ip" {
value = module.web_server.public_ip
}
output "api_server_ip" {
value = module.api_server.public_ip
}
# 使用 Terraform Registry 上的模块
module "vpc" {
source = "alibaba/vpc/alicloud"
version = "1.10.0"
vpc_name = "production-vpc"
vpc_cidr = "10.0.0.0/8"
}
terraform-project/
├── environments/
│ ├── production/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ └── staging/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── terraform.tfvars
│ └── backend.tf
├── modules/
│ ├── ecs-instance/
│ ├── vpc/
│ └── security-group/
└── .gitignore

为 Terraform 项目创建 .gitignore

Terminal window
cat > .gitignore << 'EOF'
# Terraform
.terraform/
*.tfstate
*.tfstate.backup
*.tfplan
*.tfvars
!example.tfvars
# 敏感文件
*.pem
*.key
EOF

Terraform 是基础设施即代码的核心工具,将云资源的创建和管理纳入版本控制。配合 Cloud-Init 传入 user-data 和 Ansible 进行后续配置,三者共同构建出完整的自动化基础设施交付流水线。