Terraform 基础设施即代码:多云管理与自动化

FreeGuideOnline 最新 2026-06-12

Terraform 基础设施即代码实战教程

随着云原生和多云架构的普及,手动管理云资源已成为效率瓶颈。基础设施即代码(Infrastructure as Code, IaC)将基础设施的配置、编排和管理转化为可版本控制、可复用、可自动化的代码。在众多 IaC 工具中,Terraform 凭借其多云支持、声明式语法和强大的状态管理能力脱颖而出。本教程将带你从零开始,掌握使用 Terraform 进行多云管理和自动化的核心技能。

为什么选择 Terraform

Terraform 是 HashiCorp 开源的工具,使用 HCL(HashiCorp Configuration Language)定义基础设施。它的优势在于:

  • 多云与混合云:支持 AWS、Azure、GCP、阿里云等数百个提供商,同一套语法管理不同云平台。
  • 声明式配置:你描述目标状态,Terraform 自动计算和执行达到该状态所需的操作。
  • 依赖解析:自动分析资源间依赖关系,按正确顺序创建或销毁。
  • 状态管理:通过状态文件跟踪真实世界资源,支持远程后端协作。
  • 模块化:可将可复用的基础设施封装为模块,像使用函数库一样分享。

环境准备与安装

在开始之前,请确保你的系统满足以下条件:

  1. 一个主流云平台的账号(本教程以 AWS 为例,基础操作对其他云适用)。
  2. 终端工具(macOS/Linux 终端,Windows 上推荐 PowerShell 或 WSL2)。
  3. 文本编辑器,如 VS Code(建议安装 Terraform 插件以获得语法高亮)。

安装 Terraform

  1. 前往 Terraform 官网下载页,选择对应操作系统的二进制包。
  2. 解压并将可执行文件 terraform 放入系统 PATH 目录。
    • macOS/Linux 可使用 brew install terraform 或直接移动文件到 /usr/local/bin
    • Windows 可下载 .exe 文件并配置环境变量。
  3. 验证安装:
    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 服务等交互的插件。例如 awsazurermgoogle。需在配置中声明所需版本。
  • Resource(资源):描述一个基础设施对象,如虚拟机、网络、DNS 记录等。它是配置中最基本的元素。
  • Data Source(数据源):用于读取已经存在的外部信息,如获取 AMI ID、可用区信息等,不创建新资源。
  • Module(模块):Terraform 配置的容器,用于封装一组关联资源,支持输入和输出变量,提升复用性。
  • State(状态):记录 Terraform 管理的资源与实际基础设施映射关系的文件。默认本地存储,推荐团队使用远程后端(如 S3 + DynamoDB)。
  • Provisioner(置备工具):在资源创建或销毁时执行脚本或配置管理工具(不推荐常规使用,应优先通过镜像或初始化脚本替代)。

第一个 Terraform 项目:部署 AWS EC2 实例

让我们从零构建一个项目,在 AWS 上启动一个可访问的 EC2 虚拟机。

  1. 新建项目目录并进入:

    mkdir learn-terraform-aws
    cd learn-terraform-aws
    
  2. 创建 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
    }
    
  3. 代码说明:

    • 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 的命令行工作流非常简洁,通常遵循三步:

  1. 初始化
    在项目目录执行:

    terraform init
    

    该命令会下载 AWS Provider 插件,初始化后端和模块。

  2. 计划
    在执行实际变更前,预览将要执行的操作:

    terraform plan
    

    Terraform 会分析配置并与当前状态对比,输出增删改的详细清单。养成先 planapply 的习惯,避免意外破坏。

  3. 应用
    确认计划无误后,执行变更:

    terraform apply
    

    终端会再次显示计划,并提示输入 yes 确认。执行成功后,你会看到输出的公网 IP。在浏览器中访问该 IP,即可看到 “Hello from Terraform” 页面。

    若要自动批准(适用于 CI/CD),可加 -auto-approve 选项:

    terraform apply -auto-approve
    

管理状态与远程后端

本地状态文件 terraform.tfstate 保存了所有资源的映射信息。团队协作时,必须使用远程后端来共享状态并防止冲突。

使用 AWS S3 + DynamoDB 作为后端

  1. 手动创建 S3 桶(如 my-terraform-state-bucket-unique)和 DynamoDB 表(如 terraform-locks,主键为 LockID,类型字符串)。
  2. main.tfterraform 块中添加后端配置:
    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
      }
    }
    
  3. 运行 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.tfvariables.tfoutputs.tf 的子目录。

创建模块

  1. 新建目录 modules/ec2-webserver,移入相关资源定义。
  2. modules/ec2-webserver/variables.tf 接收必要参数:
    variable "ami_id" {}
    variable "instance_type" {}
    variable "key_name" {}
    variable "subnet_id" {}
    variable "security_group_ids" {
      type = list(string)
    }
    
  3. 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 或标签等
    }
    
  4. 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 planapply,实现基础设施变更的自动化交付。

总结

通过本教程,你已掌握 Terraform 的基础工作流、状态管理、变量使用和模块化思想,并成功在 AWS 上部署了可访问的 Web 服务。Terraform 的强大在于其一致的声明式模型能够统一管理多云、混合云以及 SaaS 资源。继续探索官方 Registry 中的海量 Provider,实战中逐步深入网络规划、容器编排和合规策略,你将能够真正实现“基础设施即代码”带来的敏捷、可靠和可重复性。

现在是时候动手构建自己的项目了。打开终端,编写你的第一个 main.tf,让基础设施的创建变得像软件部署一样优雅。