如何排除 Terraform 故障

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

事情并不总是按计划进行:部署可能会失败,现有资源可能会意外中断,您和您的团队可能会被迫尽快解决问题。

与其他编程语言和框架相似,在Terraform中设置日志级别以获取内部工作流的见解,可以帮助您解决问题。通过记录内部操作,您可以发现暗示隐藏的错误,例如默认变量为不合适的数据类型。

在本教程中,您将验证变量总是具有合理值,您将准确指定哪些提供商和模块版本需要防止冲突,您还将启用各种级别的调试模式,这可以帮助您诊断Terraform本身的潜在问题。

前提条件

您可以通过DigitalOcean控制面板创建一个DigitalOcean个人访问代码,您可以在DigitalOcean产品文档中找到指示, How to Create a Personal Access Token

  • Terraform安装在您的本地机器上,并与DigitalOcean提供商建立了一个项目。 完成【How To Use Terraform with DigitalOcean】(https://andsky.com/tech/tutorials/how-to-use-terraform-with-digitalocean)教程的 Step 1Step 2,并确保项目文件夹命名为 terraform-troubleshooting,而不是 load balance。 在 Step 2中,不要包括 pvt_key变量和 SSH 密钥资源。

<$>[注] 注: 本教程已专门用Terraform 1.0.2进行测试。

设置版本限制

虽然使用第三方模块和提供商的能力可以最大限度地减少编写Terraform代码时的代码重复和努力,但第三方模块的开发者也可以发布新版本,这些版本可能会对您的特定代码带来突破性变化。

版本限制被指定为字符串,并在定义模块或提供商要求时传入版本参数。作为 前提条件的一部分,您已经在provider.tf中请求了digitalocean提供商。

1cat provider.tf

你会发现供应商代码如下:

 1[label terraform-troubleshooting/provider.tf]
 2terraform {
 3  required_providers {
 4    digitalocean = {
 5      source = "digitalocean/digitalocean"
 6      version = "~> 2.0"
 7    }
 8  }
 9}
10...

在这种情况下,您已向digitalocean提供商请求,并将版本设置为2.x,这意味着任何从2开始的版本都将匹配。

版本限制可能比仅仅指定一个版本更为复杂,如上文所述。它们可以包含一个或多个条件组,分开一个小节(,)。

  • >, <, >=, <=:用于比较,例如 >=1.0,需要版本等于或大于 1.0.
  • !=:为了排除特定版本--!= 1.0将拒绝使用和请求版本 1.0.
  • ~>:为了匹配指定的版本到最右边的版本部分,允许增加(~>1.5.10将匹配 1.5.101.5.11,但不会匹配 1.5.9)。

以下是包含多个组的两种版本限制的示例:

  • >=1.0, <2.0:允许从 1.0 系列的所有版本,直到 2.0
  • >1.0,!= 1.5:允许版本大于,但不等于 1.0,除了 1.5,它也排除。

要选择一个潜在的可用版本,它必须通过每个指定的限制,并与其他模块和提供商保持兼容,以及您正在使用的Terraform版本。

在本节中,您了解了如何通过指定版本限制来锁定您可以在项目中安装的模块和资源版本的范围。当您希望通过仅使用第三方代码的测试和批准版本来保持稳定时,这是有用的。

启用 Debug 模式

在您的工作流中可能存在一个错误或错误的输入,这可能会导致您的资源无法按预期提供。在这种罕见的情况下,重要的是要知道如何访问描述Terraform正在做什么的详细日志。

Terraform 暴露了TF_LOG环境变量,用于设置日志语音水平。

  • TRACE:最精致的词汇性,因为它显示了Terraform所采取的每一步,并通过内部日志产生了巨大的输出。
  • DEBUG:描述了与 TRACE相比,内部发生的事情以更简洁的方式。
  • ERROR:显示了防止Terraform继续进行的错误。
  • WARN:日志警告,可能表明错误或错误,但不至于执行。

要指定所需的日志级别,您需要将环境变量设置为相应的值:

1export TF_LOG=log_level

如果TF_LOG被定义,但该值不是列出的五个词汇性级别中的一个,Terraform 将默认设置为TRACE

您现在将定义一个 Droplet 资源,并尝试使用不同的日志级别部署它. 您将将 Droplet 定义存储在名为 `droplets.tf 的文件中,因此创建并打开它以进行编辑:

1nano droplets.tf

添加以下几行:

1[label terraform-troubleshooting/droplets.tf]
2resource "digitalocean_droplet" "test-droplet" {
3  image  = "ubuntu-18-04-x64"
4  name   = "test-droplet"
5  region = "fra1"
6  size   = "s-1vcpu-1gb"
7}

这个Droplet将运行Ubuntu 18.04 用一个CPU核心和1GB的RAM在fra1区域;你会称之为测试滴

在部署 Droplet 之前,将日志级别设置为DEBUG,运行:

1export TF_LOG=DEBUG

随后,计划下载:

1terraform plan -var "do_token=${DO_PAT}"

输出将非常长,你可以更仔细地检查它,以发现每个行都以双重支架中的语音级别(重要性)开始。

「[WARN]」和「[INFO]」也存在,这是因为「TF_LOG」设置了最低的日志级别,这意味着您必须将「TF_LOG」设置为「TRACE」以同时显示「TRACE」和所有其他日志级别。

如果发生内部错误,Terraform会显示堆栈跟踪和输出,停止执行。从那里,您将能够找到错误发生在源代码中的位置,如果是错误,请向Terraform开发人员报告。

以下是当DigitalOcean后端无法验证您的API代币时,日志输出会是怎样的。

 1[secondary_label Output]
 2...
 3digitalocean_droplet.test-droplet: Creating...
 42021/01/20 06:54:35 [ERROR] eval: *terraform.EvalApplyPost, err: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
 52021/01/20 06:54:35 [ERROR] eval: *terraform.EvalSequence, err: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
 6
 7Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
 8
 9  on droplets.tf line 1, in resource "digitalocean_droplet" "test-droplet":
10   1: resource "digitalocean_droplet" "test-droplet" {
11   ...

若要禁用调试模式并将日志语音性重置为默认级别,请通过运行清除TF_LOG环境变量:

1unset TF_LOG

您现在已经学会了如何启用更多可言的日志模式. 它们对于诊断碰撞和意外的Terraform行为非常有用。 在下一节中,您将审查验证变量和防止边缘案例。

变量验证

在本节中,您将确保变量根据其类型和验证参数始终具有合理和适当的值。

在 HCL(HashiCorp Configuration Language)中,在定义变量时,您不一定需要指定任何东西,除了它的名称。

1variable "test_ip" { }

然后,您可以通过代码使用此值,在运行 Terraform 时传输其值。

虽然这将奏效,但这个定义有两个缺点:首先,你不能在运行时传输一个值;其次,它可以是任何类型的(‘bool’、‘string’ 等),这可能不适合它的目的。

1variable "test_ip" {
2  type    = string
3  default = "8.8.8.8"
4}

通过设置默认值,您可以确保引用变量的代码在未提供更具体的值的情况下仍然运行。当您指定类型时,Terraform 可以验证该变量应该设置的新值,并显示错误,如果它不符合类型。

您可以为变量提供验证流程,如果验证失败,可以发出错误消息. 验证的例子是检查新值的长度,如果它是一个字符串,或者在结构化数据的情况下,寻找至少一个与 RegEx 表达式的匹配。

若要将输入验证添加到变量中,请定义一个验证块:

1variable "test_ip" {
2  type    = string
3  default = "8.8.8.8"
4
5  validation {
6    condition     = can(regex("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", var.test_ip))
7    error_message = "The provided value is not a valid IP address."
8  }
9}

验证下,您可以指定两种参数:

  • 接受它计算的条件,这意味着验证是否通过。
  • 指定错误消息的错误消息,如果验证未通过。

在本示例中,您通过在变量值中搜索regex匹配来计算条件,然后将其传送到可以函数,如果作为参数传输的函数运行没有错误,则可以函数返回,因此用于检查函数成功完成或返回结果。

我们在这里使用的regex函数接受一个 **Regular **Express (RegEx),将其应用到给定的字符串中,并返回相匹配的字符串。

现在您知道如何为变量指定默认值,如何设置其类型,以及如何使用 RegEx 表达式启用输入验证。

结论

在本教程中,您通过启用调试模式并将日志词汇率设置为适当水平来解决Terraform问题,您还了解了变量的一些先进功能,例如声明验证程序和设置良好的默认值。

为了您的项目的稳定性,建议锁定第三方模块和提供商版本,因为在必要时,它会留给您一个稳定的系统和升级路径。

对变量输入值的验证不限于与regex匹配. 有关您可以使用的更多内置函数,请访问 官方文件

本教程是《如何使用Terraform管理基础设施》系列的一部分,该系列涵盖了许多Terraform主题,从首次安装Terraform到管理复杂项目。

Published At
Categories with 技术
comments powered by Disqus