Terraform基础设施即代码入门:自动化创建和管理香港VPS的完整实战

Infrastructure as Code(基础设施即代码)是现代DevOps的核心实践——用代码描述服务器、网络、DNS等基础设施,像管理代码一样管理服务器:版本控制、代码审查、自动化部署、一键回滚。Terraform是目前最主流的IaC工具,本文带你从零上手。

一、为什么要用Terraform?

  • 可重现性:同一套Terraform代码在任何环境下都能创建出一模一样的基础设施
  • 版本控制:基础设施变更记录在Git中,每次修改可追溯、可审计
  • 协作友好:团队成员通过Pull Request审查基础设施变更,比手动操作更安全
  • 灾难恢复:服务器全损后,运行一条命令即可在几分钟内重建完整环境
  • 成本控制:精确知道创建了哪些资源,避免忘记关闭的闲置资源持续计费

二、安装Terraform

# Ubuntu/Debian
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor \
    | tee /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
    https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
    | tee /etc/apt/sources.list.d/hashicorp.list

apt update && apt install terraform -y

# 验证安装
terraform --version
# 输出:Terraform v1.7.x

三、Terraform核心概念

概念说明类比
Provider与云服务商API交互的插件数据库驱动
Resource要创建的基础设施资源(服务器、DNS等)数据库表记录
StateTerraform记录已创建资源的状态文件数据库当前数据
Plan预览将要执行的变更SQL的EXPLAIN
Apply实际执行变更执行SQL
Destroy销毁所有由Terraform管理的资源DELETE FROM

四、项目目录结构

terraform-vps/
├── main.tf          # 主要资源定义
├── variables.tf     # 变量声明
├── outputs.tf       # 输出值定义
├── terraform.tfvars # 变量赋值(敏感信息,不提交Git)
├── providers.tf     # Provider配置
└── modules/
    ├── web-server/  # Web服务器模块
    └── database/    # 数据库模块

五、使用Cloudflare Provider管理DNS

以Cloudflare为例,展示如何用Terraform自动管理DNS记录(Provider支持取决于服务商是否提供Terraform集成):

# providers.tf
terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
  }
}

provider "cloudflare" {
  api_token = var.cloudflare_api_token
}
# variables.tf
variable "cloudflare_api_token" {
  description = "Cloudflare API Token"
  type        = string
  sensitive   = true
}

variable "domain" {
  description = "主域名"
  type        = string
  default     = "yourdomain.com"
}

variable "server_ip" {
  description = "香港VPS公网IP"
  type        = string
}
# main.tf — DNS记录管理
data "cloudflare_zone" "main" {
  name = var.domain
}

# 主域名A记录
resource "cloudflare_record" "root" {
  zone_id = data.cloudflare_zone.main.id
  name    = "@"
  value   = var.server_ip
  type    = "A"
  ttl     = 300
  proxied = true  # 开启Cloudflare代理(橙云)
}

# www子域名
resource "cloudflare_record" "www" {
  zone_id = data.cloudflare_zone.main.id
  name    = "www"
  value   = var.server_ip
  type    = "A"
  ttl     = 300
  proxied = true
}

# mail子域名(邮件服务器,不走CDN)
resource "cloudflare_record" "mail" {
  zone_id = data.cloudflare_zone.main.id
  name    = "mail"
  value   = var.server_ip
  type    = "A"
  ttl     = 300
  proxied = false
}

# SPF记录
resource "cloudflare_record" "spf" {
  zone_id = data.cloudflare_zone.main.id
  name    = "@"
  value   = "v=spf1 ip4:${var.server_ip} ~all"
  type    = "TXT"
  ttl     = 3600
}

# MX记录
resource "cloudflare_record" "mx" {
  zone_id  = data.cloudflare_zone.main.id
  name     = "@"
  value    = "mail.${var.domain}"
  type     = "MX"
  ttl      = 3600
  priority = 10
}

# Cloudflare防火墙规则:封禁已知爬虫
resource "cloudflare_ruleset" "block_bots" {
  zone_id     = data.cloudflare_zone.main.id
  name        = "Block known bad bots"
  description = "封禁恶意爬虫和扫描器"
  kind        = "zone"
  phase       = "http_request_firewall_custom"

  rules {
    action      = "block"
    description = "封禁已知恶意UA"
    enabled     = true
    expression  = "(http.user_agent contains \"zgrab\") or (http.user_agent contains \"masscan\") or (http.user_agent contains \"sqlmap\")"
  }
}
# outputs.tf
output "zone_id" {
  description = "Cloudflare Zone ID"
  value       = data.cloudflare_zone.main.id
}

output "nameservers" {
  description = "Cloudflare分配的NS服务器"
  value       = data.cloudflare_zone.main.name_servers
}
# terraform.tfvars(不提交到Git,添加到.gitignore)
cloudflare_api_token = "你的Cloudflare API Token"
domain               = "yourdomain.com"
server_ip            = "你的香港VPS IP"

六、执行Terraform工作流

# 1. 初始化(下载Provider插件)
terraform init

# 2. 验证配置语法
terraform validate

# 3. 预览将要执行的变更(不实际操作)
terraform plan

# 输出示例:
# + cloudflare_record.root  将创建A记录
# + cloudflare_record.www   将创建www记录
# Plan: 5 to add, 0 to change, 0 to destroy.

# 4. 执行变更
terraform apply
# 输入 yes 确认

# 5. 查看当前状态
terraform show

# 6. 销毁所有资源(谨慎使用!)
terraform destroy

七、远程State存储(团队协作)

默认State文件存在本地,多人协作时需要使用远程State:

# 使用Terraform Cloud(免费)存储State
terraform {
  cloud {
    organization = "你的组织名"
    workspaces {
      name = "hongkong-vps-production"
    }
  }
}
# 或使用S3兼容存储(如Cloudflare R2)
terraform {
  backend "s3" {
    bucket                      = "terraform-state"
    key                         = "production/terraform.tfstate"
    region                      = "auto"
    endpoint                    = "https://账号ID.r2.cloudflarestorage.com"
    access_key                  = "R2 Access Key"
    secret_key                  = "R2 Secret Key"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
  }
}

八、总结

Terraform将基础设施管理从"手动操作控制台"升级为"代码定义基础设施",特别适合需要管理多台服务器、多个DNS记录、多个防火墙规则的中大型项目。从DNS管理开始学习Terraform是最低风险的入门路径——即使操作失误,也只是DNS记录变化,无需担心服务器数据丢失。IDC.Net的香港服务器可以作为Terraform管理的目标基础设施,配合Cloudflare Provider实现从服务器到DNS的全链路自动化管理。

THE END