一般样式和结构最佳实践

本文档提供了适用于 Terraform 配置的基本样式和结构建议。这些建议适用于可重复使用的 Terraform 模块和根配置。

本指南未介绍 Terraform。如需了解如何将 Terraform 与 Google Cloud 搭配使用,请参阅 Terraform 使用入门

遵循标准模块结构

  • Terraform 模块必须遵循标准模块结构
  • 使用 main.tf 文件启动每个模块,默认情况下,资源位于此文件中。
  • 在每个模块中,添加 Markdown 格式的 README.md 文件。在 README.md 文件中,添加有关模块的基本文档。
  • 将示例放在 examples/ 文件夹中,并为每个示例提供单独的子目录。对于每个示例,请添加详细的 README.md 文件。
  • 使用资源各自的文件和描述性名称(例如 network.tfinstances.tfloadbalancer.tf)创建资源的逻辑分组。
    • 避免为每个资源提供自己的文件。按共享用途对资源进行分组。例如,在 dns.tf 中组合使用 google_dns_managed_zonegoogle_dns_record_set
  • 在模块的根目录中,仅添加 Terraform (*.tf) 和代码库元数据文件(例如 README.mdCHANGELOG.md)。
  • 将任何其他文档放在 docs/ 子目录中。

采用命名惯例

  • 使用下划线命名所有配置对象,以分隔多个字词。这种做法可确保与资源类型、数据源类型和其他预定义值的命名惯例保持一致。此惯例不适用于名称参数

    推荐:

    resource "google_compute_instance" "web_server" {
      name = "web-server"
    }
    

    不推荐:

    resource "google_compute_instance" "web-server" {
      name = "web-server"
    }
    
  • 如需简化对唯一属于其类型的资源(例如,整个模块的单个负载均衡器)的引用,请将该资源命名为 main

    • 记住 some_google_resource.my_special_resource.idsome_google_resource.main.id 需要花费额外的精力。
  • 如需区分属于同一类型的资源(例如 primarysecondary),请提供有意义的资源名称。

  • 将资源名称设为单数形式。

  • 在资源名称中,请不要重复资源类型。例如:

    推荐:

    resource "google_compute_global_address" "main" { ... }
    

    不推荐:

    resource "google_compute_global_address" "main_global_address" { … }
    

谨慎使用变量

  • variables.tf 中声明所有变量。
  • 为变量提供与其用法或用途相关的描述性名称:
    • 表示数值的输入、局部变量和输出(例如磁盘大小或 RAM 大小)必须使用单位命名(例如 ram_size_gb)。Google Cloud API 没有标准单位,因此使用单位命名变量可让配置维护人员清楚地了解预期输入单位。
    • 对于存储单位,请使用二进制单位前缀(1024 的幂)- kibimebigibi。对于所有其他计量单位,请使用十进制单位前缀(1000 的幂)- kilomegagiga。此用法与 Google Cloud 中的用法一致。
    • 如需简化条件逻辑,请为布尔值变量提供正名称,例如 enable_external_access
  • 变量必须有说明。说明会自动包含在已发布模块的自动生成的文档中。说明为新开发者添加了描述性名称无法提供的其他背景信息。
  • 为变量提供定义的类型。
  • 在适当情况下,请提供默认值:
    • 对于具有与环境无关的值的变量(例如磁盘大小),请提供默认值。
    • 对于具有特定于环境的值的变量(例如 project_id),请勿提供默认值。这样,调用模块必须提供有意义的值。
  • 仅当变量保留为空是底层 API 不拒绝的有效偏好设置时才对变量(例如空字符串或列表)使用空默认值。
  • 请谨慎使用变量。参数化的值必须根据每个实例或环境而变化。在决定是否公开某个变量时,请确保您拥有更改该变量的具体用例。如果只有极少数可能需要变量,请不要公开该变量。
    • 添加具有默认值的变量是向后兼容的。
    • 移除变量是向后不兼容的。
    • 如果在多个位置重复使用字面量,您可以使用局部值,而无需将其作为变量公开。

公开输出

  • outputs.tf 文件中整理所有输出。
  • 为所有输出提供有意义的说明。
  • README.md 文件中记录输出说明。使用 terraform-docs 等工具在提交时自动生成说明。
  • 输出根模块可能需要引用或共享的所有有用值。特别是对于开源模块或频繁使用的模块,请公开所有可能消耗的输出。
  • 请勿直接通过输入变量传递输出,因为这样做会阻止输出正确地添加到依赖关系图中。为确保已创建隐式依赖项,请务必从资源中输出引用特性。传递特性,而不是直接引用实例的输入变量,如下所示:

    推荐:

    output "name" {
      description = "Name of instance"
      value       = google_compute_instance.main.name
    }
    

    不推荐:

    output "name" {
      description = "Name of instance"
      value       = var.name
    }
    

使用数据源

  • 数据源放在引用它们的资源旁边。例如,如果要提取要在启动实例中使用的映像,请将其与实例放在一起,而不是在各自的文件中收集数据资源。
  • 如果数据源数量很大,请考虑将它们移动到专用 data.tf 文件中。
  • 如需提取相对于当前环境的数据,请使用变量或资源插值类型

限制自定义脚本的使用

  • 仅在必要时使用脚本。Terraform 不会考虑或管理通过脚本创建的资源的状态。
    • 尽可能避免使用自定义脚本。仅在 Terraform 资源不支持所需行为时使用它们。
    • 使用的任何自定义脚本都必须有明确记录的存在原因,并且最好有弃用方案。
  • Terraform 可以通过预配工具(包括 local-exec 预配工具)调用自定义脚本。
  • 将 Terraform 调用的自定义脚本放在 scripts/ 目录中。

在单独的目录中添加辅助脚本

  • helpers/ 目录中整理非 Terraform 调用的辅助脚本。
  • README.md 文件中记录辅助脚本,其中包含说明和调用示例。
  • 如果辅助脚本接受参数,请提供参数检查和 --help 输出。

将静态文件放在单独的目录中

  • Terraform 引用但未执行(例如加载到 Compute Engine 实例上的启动脚本)的静态文件必须整理到 files/ 目录中。
  • 将冗长的 HereDoc 放在外部文件(独立于其 HCL)中。使用 file() 函数引用它们。
  • 对于使用 Terraform templatefile 函数读入的文件,请使用文件扩展名 .tftpl
    • 模板必须放在 templates/ 目录中。

保护有状态资源

对于有状态资源(例如数据库),请确保启用删除保护。例如:

resource "google_sql_database_instance" "main" {
  name = "primary-instance"
  settings {
    tier = "D0"
  }

  lifecycle {
    prevent_destroy = true
  }
}

使用内置格式设置

所有 Terraform 文件都必须符合 terraform fmt 的标准。

限制表达式的复杂性

  • 限制任何单个插值表达式的复杂性。如果单个表达式中需要许多函数,请考虑使用局部值将其拆分为多个表达式。
  • 一行中不能有多个三元运算。请改用多个本地值来构建逻辑。

为条件值使用 count

如需有条件地实例化资源,请使用 count 元参数。例如:

variable "readers" {
  description = "..."
  type        = list
  default     = []
}

resource "resource_type" "reference_name" {
  // Do not create this resource if the list of readers is empty.
  count = length(var.readers) == 0 ? 0 : 1
  ...
}

使用用户指定的变量为资源设置 count 变量时,请务必小心。如果为此类变量(如 project_id)提供了资源特性,但该资源尚不存在,则 Terraform 无法生成计划。相反,Terraform 会报告错误 value of count cannot be computed。在这种情况下,请使用单独的 enable_x 变量来计算条件逻辑。

为迭代资源使用 for_each

如果要根据输入资源创建资源的多个副本,请使用 for_each 元参数。

将模块发布到注册表

后续步骤