【问题标题】:How can I debug custom terraform provider which I have implemented如何调试已实现的自定义 terraform 提供程序
【发布时间】:2021-05-05 13:36:58
【问题描述】:
我已经实现了一个 kubernetes terraform 提供程序,它将清单文件应用于 k8s 集群。我也创建了 .tf 文件,但是当我运行 terraform init 时,它会从 terraform 注册表下载插件。
如何让我的插件运行适用于 terraform。
【问题讨论】:
标签:
terraform
terraform0.12+
terraform-template-file
terraform-provider-kubernetes
【解决方案1】:
调试 TerraForm 提供程序
了解设计
为了做到这一点,您首先必须了解 Go 如何构建应用程序,然后了解 terraform 如何使用它。
每个 terraform 提供者都是一种module。为了支持几乎任何语言的开放模块化系统,您需要能够动态加载模块并与它们交互。 Terraform 也不例外。
然而,go lang 团队很久以前就决定编译成静态链接的应用程序;
您拥有的任何依赖项都将被编译为 1 个单个二进制文件。与其他本地语言(如 C 或 C++)不同,a
未使用.dll 或.so;在运行时没有动态库可以加载,因此,模块化变成了另一个技巧。
这样做是为了避免臭名昭著的 dll 地狱,直到大多数现代系统都包含一些
一种依赖管理。是的,这仍然是个问题。
每个 terraform 提供者都是它自己的迷你 RPC 服务器。当 terraform 运行您的提供程序时,它实际上会启动一个作为您的提供程序的新进程,并通过
此 RPC 通道。使问题更加复杂的是,您的提供程序进程的生命周期非常长
短暂的;可能持续不超过几秒钟。这是您需要与调试器连接的过程
正常调试
通常,您会直接启动您的应用程序,它会将模块加载到应用程序内存中。这就是为什么你实际上可以
调试它,因为您的调试器知道如何为您的提供者找到确切的内存地址。然而,你没有
这种安排,你需要做一个远程调试会话。
难题
因此,您不会直接加载 terraform,即使您这样做了,您的 module(也称为您的提供者)也在内存中
完全不同过程的空间;并且可能持续不超过几秒钟。
解决方案
- 你需要调试工具delve。
- 您必须在代码中要开始的位置附近放置一些 shim 代码
调试。我们需要在连接之前阻止此提供程序进程退出。所以,把这段代码放在适当的位置:
connected := false
for !connected {
time.Sleep(time.Second) // set breakpoint here
}
这段代码有效地创建了一个无限睡眠循环;但这实际上对于解决问题至关重要。
- 在此循环内放置一个断点。它还不会做任何事情。
- 现在运行您需要的 terraform 命令,以使用您希望调试的代码。这样做后,
terraform 基本上会停止,因为它会等待您的提供商的响应;因为你在里面放了一个无限的睡眠循环
- 您现在必须告诉
delve 使用它的PID 连接到这个远程进程。这并不像看起来那么难。
运行以下命令:
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $(pgrep terraform-provider-artifactory)
最后一个参数为您的提供者获取PID 并将其提供给delve 以进行连接。立即运行此
命令,你将达到你的断点。请确保将 terraform-provider-artifactory 替换为您的提供商名称
- 要退出此无限循环,请使用调试器将
connected 设置为true。通过这样做,您可以更改循环谓词
它将在下一次迭代中退出此循环。
-
调试! - 此时,您可以执行、监视、删除调用堆栈等操作。您的整个武器库都可用