1. 概述

在我们之前的文章《Terraform 基础概念与使用》中,我们介绍了 Terraform 的基本用法。本文将进一步探讨使用 Terraform 时的一些最佳实践,帮助你在实际项目中更好地组织代码、管理状态和协作开发。


2. 资源文件组织结构

刚开始使用 Terraform 时,我们可能会把所有资源定义、变量和输出都放在一个文件中。这种做法虽然简单,但随着项目规模增长,代码将变得难以维护和复用。

推荐做法:利用 Terraform 在模块内自动读取所有 .tf 文件的特性,按功能将内容分文件管理。虽然资源声明顺序对 Terraform 无影响,但良好的组织结构有助于理解和协作。

常见的文件结构如下:

  • variables.tf:定义模块输入变量,含默认值(如适用)
  • main.tf:核心资源定义,建议保持简洁,遵循单一职责原则
  • modules/:存放子模块(如有)
  • outputs.tf:定义输出变量
  • providers.tf:仅用于顶层模块,声明所用的 Provider 及其版本

⚠️ 注意:当 main.tf 文件变得臃肿时,应考虑将其拆分为多个子模块,比如将 EC2 实例与其绑定的 EBS 卷封装为一个模块。


3. 模块使用规范

模块是 Terraform 提供的复用机制,但如何设计模块结构是关键。我们可以借鉴软件工程中 S.O.L.I.D 原则中的 单一职责原则(Single Responsibility Principle)

建议:每个模块只关注一个基础设施方面,比如创建 VPC、部署虚拟机等。

以下是一个典型项目结构示例:

$ tree .
├── main.tf
├── modules
│   ├── ingress
│   │   └── www.petshop.com.br
│   │       ├── main.tf
│   │       ├── outputs.tf
│   │       └── variables.tf
│   └── SvcFeedback
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf
├── terraform.tfvars
└── variables.tf

每个模块包含:

  • variables.tf:输入变量
  • main.tf:资源定义
  • outputs.tf:输出变量

这种结构有助于模块使用者快速理解接口(即变量与输出),而无需关心具体实现。


4. Provider 配置管理

Terraform 中的 Provider 是与云平台交互的关键组件,通常需要配置访问密钥、区域等敏感信息。

不推荐做法:将敏感信息硬编码在代码中。

4.1 使用变量配置 Provider

通过定义变量来传递敏感信息:

variable "aws_region" {
  type = string
}

variable "aws_access_key" {
  type = string
}

variable "aws_secret_key" {
  type = string
}

然后在 provider 声明中使用:

provider "aws" {
  region     = var.aws_region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}

变量值可以通过 .tfvars 文件或环境变量传入:

# aws.tfvars
aws_access_key = "xxxxx"
aws_secret_key = "yyyyy"
aws_region     = "us-east-1"

运行命令时也可以混合使用环境变量和命令行参数:

$ export TF_VAR_aws_region="us-east-1"
$ terraform plan -var="access_key=xxxx" -var-file=./aws.tfvars

Terraform 默认会读取 terraform.tfvars 和所有以 .auto.tfvars 结尾的文件。

4.2 利用 Provider 的默认配置机制

某些 Provider 支持从本地配置文件读取凭证,比如 Kubernetes Provider 可以直接使用 kubectl 的上下文配置。

优势:省去手动配置,提高安全性。


5. State 管理

Terraform 的 State 文件记录了当前基础设施的状态,包含敏感信息,必须妥善管理。

推荐做法

  • .tfstate 文件加入 .gitignore,避免提交到版本控制系统
  • 尽早使用远程后端(Remote Backend)代替默认的本地存储
  • 启用 State 锁定机制,避免并发冲突

5.1 远程 Backend 配置示例

以 PostgreSQL 为例:

terraform {
  backend "pg" {}
}

远程后端通常需要额外配置,建议通过环境变量或 .auto.tfvars 文件传入。

优势

  • 支持多用户协作
  • 提供 State 锁定功能,防止并发操作冲突

5.2 推荐使用自动化工具运行 Terraform

建议将 Terraform 部署过程集成到 CI/CD 流程中,例如 Jenkins、GitLab CI 等。

中小型团队也可以考虑使用 Terraform Cloud 的免费版本进行统一管理。


6. Workspaces 使用建议

Workspaces 允许我们在同一套代码下维护多个 State,适用于管理多个环境(如 DEV/QA/PRD)。

推荐做法:以环境名称命名 Workspaces,例如 DEV, QA, PRD,便于识别。

如果多个团队协作开发,也可以加入团队名称,例如 DEV-SQUAD1, DEV-SUPPORT

⚠️ 注意:不同 Workspace 的变量配置可能不同,建议通过 .tfvars 文件控制。


7. 自动化测试实践

随着基础设施代码化(IaC)的推进,测试变得越来越重要,尤其是在模块开发中。

建议测试内容

  • 可访问性:资源是否成功创建?是否可达?
  • 安全性:是否有不必要的端口开放?是否禁用了默认账户?
  • 正确性:模块是否正确使用输入参数?是否对缺失参数做出反馈?

Terraform 的测试生态仍在演进中,目前可以使用如下方式:

  • 使用测试框架:FitNesse、Spock、Protractor 等
  • 使用 Shell 脚本编写集成测试
  • 集成到 CI/CD 流程中自动运行

⚠️ 提示:建议优先编写集成测试,而不是单元测试,因为基础设施本身是集成性很强的系统。


8. 总结

本文介绍了 Terraform 使用中的一些最佳实践,包括资源文件组织、模块设计、Provider 配置、State 管理、Workspaces 使用及测试策略。

由于基础设施即代码(IaC)仍处于快速发展阶段,这些实践只是一个起点。随着社区的不断演进,我们也将看到更多新工具和新模式的出现。

如需参考完整示例代码,请查看 GitHub 项目:Terraform Best Practices 示例代码


原始标题:Best Practices When Using Terraform