如何测试 Terraform 模板而不是反复试验

How to test terraform templates other than trial and error

我正在使用 Terraform 创建云资源。每个资源在供应后都应处于特定的期望状态。例如,当我创建一个 Google Cloud Bucket 时,我希望自动应用某些权限。因此,我的计划包含必要的代码,但我想在申请之前确保它始终有效。有什么测试 tool/library 可以帮到这里吗?

terraform plan 命令旨在预览应用计划时 Terraform 将进行哪些更改,这是我们在不触及 "real" 的情况下最接近测试 Terraform 配置的方法API.

对于这还不够的情况,通常会以不同的状态多次部署相同的配置,从而允许将一个配置用作 "staging" 环境来测试更改,而不会影响主要环境。 Terraform 0.9 中添加的 State Environments 功能可以使这更容易,因为可以使用 Terraform CLI 命令直接管理多个环境状态。

当谈到结果的自动化测试时,目前还没有完整的解决方案集成到 Terraform 中,但是有一些构建块可能有助于用单独的编程语言编写测试。

Terraform 生成 JSON 格式的状态文件,原则上,外部程序可以使用这些文件来提取有关 Terraform 创建内容的某些数据。虽然这种格式尚未被认为是正式稳定的,但实际上它的变化很少,以至于人们已经成功地与之集成,并接受他们在升级 Terraform 时可能需要进行调整。

这里采用何种策略在很大程度上取决于您要测试的具体内容。例如:

  • 在启动虚拟服务器的环境中,Serverspec can be used to run tests from the perspective of these servers. This can either be run separately from Terraform using some out-of-band process, or as part of the Terraform apply using the remote-exec provisioner 等工具。这允许验证诸如 "can the server reach the database?" 之类的问题,但不适用于诸如 "is the instance's security group restrictive enough?" 之类的问题,因为鲁棒性检查需要从实例本身外部访问数据。

  • 可以使用现有的测试框架编写测试(例如 RSpec 用于 Ruby,unittest 用于 Python,等等)从 Terraform 状态文件收集相关资源 ID 或地址,然后使用相关平台的 SDK 检索有关资源的数据并断言它们已按预期设置。这是先前想法的更一般形式,运行从被测基础设施外部主机的角度进行测试,因此可以收集更广泛的数据集对

  • 进行断言
  • 对于更适度的需求,人们可以选择相信 Terraform 状态是对现实的准确表示(在许多情况下是一个有效的假设)并直接断言。这最适合简单的 "lint-like" 情况,例如验证是否遵循正确的资源标记方案以进行成本分配。

a relevant Terraform Github issue 中对此有更多讨论。

在最新版本的 Terraform 中,强烈建议对任何非玩具应用程序使用远程后端,但这意味着状态数据不能直接在本地磁盘上使用。但是,可以使用 terraform state pull 命令从远程后端检索它的快照,该命令将 JSON 格式的状态数据打印到标准输出,以便它可以被调用程序捕获和解析。

是的,我之前也是这么想的。目前,我在应用新的 terraform 更改时使用多种方法来降低风险。

他们不能保证 100% 成功 terraform apply,但会在您应用之前​​解决大部分问题。

  1. 验证 terraform 配置文件。

Terraform 有 validate function 开始。但它不够智能,无法遍历子文件夹。我创建了一个小的 shell 函数,并在 terraform apply.

之前自动将 CI/CD 管道添加到 运行
validate() {
  modules=$(find . -type f -name "*.tf" -exec dirname {} \;|sort -u)
  for m in ${modules}
  do
    (terraform validate "$m" && echo "√ $m") || exit 1
  done
}

当然,在提交更改之前 terraform fmt 是个不错的主意。

  1. terraform plan

@Martin Atkins 已经解释过了,terraform.io 有关于这个命令的详细信息。

  1. 运行自动化测试厨房。

这是用于测试 Terraform 配置的测试 Kitchen 插件

https://github.com/newcontext-oss/kitchen-terraform

这是一个集成测试。测试将 运行 在单独的 VPC 中,与您添加的测试用例一样多。在 CI/CD 管道中添加自动化测试,以便每次向 master 分支提出合并请求时触发自动化测试。仅在通过测试后应用更改。

我们最近开源了 Terratest,我们用于测试基础设施代码的瑞士军刀。

今天,您可能正在通过部署、验证和取消部署来手动测试所有基础架构代码。 Terratest 帮助您自动执行此过程:

  1. 用 Go 编写测试。
  2. 在 Terratest 中使用助手来执行您真正的 IaC 工具(例如 Terraform、Packer 等),以在真实环境(例如 AWS)中部署真实的基础设施(例如服务器)。请注意,此环境将是一个单独的 "sandbox" 帐户,而不是产品!
  3. 在 Terratest 中使用助手通过发出 HTTP 请求、API 调用、SSH 连接等来验证基础架构在该环境中是否正常工作
  4. 在 Terratest 中使用助手在测试结束时取消部署所有内容。

下面是一些 Terraform 代码的示例测试:

terraformOptions := &terraform.Options {
  // The path to where your Terraform code is located
  TerraformDir: "../examples/terraform-basic-example",
}

// This will run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)

// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)

// Run `terraform output` to get the value of an output variable
instanceUrl := terraform.Output(t, terraformOptions, "instance_url")

// Verify that we get back a 200 OK with the expected text
// It can take a minute or so for the Instance to boot up, so retry a few times
expected := "Hello, World"
maxRetries := 15
timeBetweenRetries := 5 * time.Second
http_helper.HttpGetWithRetry(t, instanceUrl, 200, expected, maxRetries, timeBetweenRetries)

这些是集成测试,根据您测试的内容,可能需要 5 到 50 分钟。它并不快(尽管使用 Docker and test stages,您可以加快 一些 的速度),并且您必须努力使测试可靠,但值得花时间.

查看 Terratest repo 文档和大量各种类型的基础结构代码示例以及它们的相应测试。