Terraformer - 基础设施到代码

Terraformer - 基础设施到代码
我想向您介绍一下我为解决老问题而编写的新 CLI 工具。

问题

Terraform 长期以来一直是 DevOps/云/IT 社区的标准。 这对于处理基础设施即代码来说非常方便和有用。 Terraform 中有许多乐趣,还有许多叉子、锋利的刀子和耙子。
使用 Terraform,创建新事物然后管理、更改或删除它们非常方便。 那些在云中拥有庞大基础设施但不是通过 Terraform 创建的人应该做什么? 重写和重新创建整个云在某种程度上是昂贵且不安全的。
我在 2 份工作中遇到了这个问题,最简单的例子是,当你希望所有内容都以 terraform 文件的形式存在于 Git 中时,但你有 250 多个存储桶,并且手动将它们写入 terraform 中,需要很多时间。
问题 自 2014 年以来,terrafom 于 2016 年关闭,希望能够进口。

一般来说,一切都是如图所示,只是从右到左

警告:作者半生不在俄罗斯生活,很少用俄语写作。 当心拼写错误。

解决方案

1.AWS有现成的和旧的解决方案 地形。 当我试图让我的 250 多个水桶通过它时,我意识到那里的一切都很糟糕。 AWS 长期以来一直在引入许多新选项,但 terraforming 并不了解它们,一般来说它是 ruby 模板看起来稀疏。 晚上2点后我发了 拉取请求 在那里添加更多功能,并意识到这样的解决方案根本不合适。
terraforming 的工作原理:它从 AWS SDK 获取数据并通过模板生成 tf 和 tfstate。
这里有3个问题:
1. 更新总会有滞后
2. tf 文件有时会损坏
3. tfstate与tf分开收集,并不总是收敛
一般来说,很难得到“terraform plan”说没有变化的结果

2. `terraform import` 是 terraform 中的内置命令。 它是如何工作的?
您编写一个包含资源名称和类型的空 TF 文件,然后运行“terraform import”并传递资源 ID。 terraform 联系提供商、接收数据并创建 tfstate 文件。
这里有3个问题:
1.我们只得到一个tfstate文件,并且tf是空的,需要手动写入或者从tfstate转换
2. 一次只能使用一种资源,不支持所有资源。 我又该如何处理 250 多个桶呢?
3.您需要知道资源的ID - 也就是说,您需要将其包装在获取资源列表的代码中
一般来说,结果是部分的并且不能很好地扩展

我的决定

要求:
1.能够为资源创建tf和tfstate文件。 例如,下载所有存储桶/安全组/负载均衡器,“terraform plan”返回没有任何更改
2.您需要2个GCP + AWS云
3.全局解决方案,每次更新都很方便,不会在每个资源上浪费3天的工作时间
4. 开源——每个人都有同样的问题

Go 语言是我喜欢它的原因,它有一个用于创建 terraform 中使用的 HCL 文件的库 + terraform 中的大量代码可能很有用

路径

第一次尝试
我从一个简单的版本开始。 通过 SDK 联系云以获取所需资源并将其转换为 terraform 的字段。 该尝试在安全组上立即失败,因为我不喜欢仅转换安全组的 1.5 天(而且有很多资源)。 很长一段时间然后可以更改/添加字段

第二次尝试
基于所描述的想法 这里。 只需将 tfstate 转换为 tf. 所有数据都在那里并且字段是相同的。 如何获取许多资源的完整 tfstate? 这就是“terraform refresh”命令发挥作用的地方。 terraform 获取 tfstate 中的所有资源,并根据 ID 提取其中的数据并将所有内容写入 tfstate。 也就是说,创建一个仅包含名称和 ID 的空 tfstate,运行“terraformfresh”,然后我们会获得完整的 tfstate。 万岁!
现在让我们来递归地编写一个 tfstate 到 tf 的转换器。 对于那些从未读过 tfstate 的人来说,它是 JSON,但很特别。
这是它的重要部分属性

 "attributes": {
                            "id": "default/backend-logging-load-deployment",
                            "metadata.#": "1",
                            "metadata.0.annotations.%": "0",
                            "metadata.0.generate_name": "",
                            "metadata.0.generation": "24",
                            "metadata.0.labels.%": "1",
                            "metadata.0.labels.app": "backend-logging",
                            "metadata.0.name": "backend-logging-load-deployment",
                            "metadata.0.namespace": "default",
                            "metadata.0.resource_version": "109317427",
                            "metadata.0.self_link": "/apis/apps/v1/namespaces/default/deployments/backend-logging-load-deployment",
                            "metadata.0.uid": "300ecda1-4138-11e9-9d5d-42010a8400b5",
                            "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",

有:
1. id - 字符串
2. 元数据 - 一个大小为 1 的数组,其中包含一个带有字段的对象,如下所述
3.spec - 大小为1的散列和其中的键、值
简而言之,一种有趣的格式,一切都可以深入几个层次

                   "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",
                            "spec.0.selector.0.match_expressions.#": "0",
                            "spec.0.selector.0.match_labels.%": "1",
                            "spec.0.selector.0.match_labels.app": "backend-logging-load",
                            "spec.0.strategy.#": "0",
                            "spec.0.template.#": "1",
                            "spec.0.template.0.metadata.#": "1",
                            "spec.0.template.0.metadata.0.annotations.%": "0",
                            "spec.0.template.0.metadata.0.generate_name": "",
                            "spec.0.template.0.metadata.0.generation": "0",
                            "spec.0.template.0.metadata.0.labels.%": "1",
                            "spec.0.template.0.metadata.0.labels.app": "backend-logging-load",
                            "spec.0.template.0.metadata.0.name": "",
                            "spec.0.template.0.metadata.0.namespace": "",
                            "spec.0.template.0.metadata.0.resource_version": "",
                            "spec.0.template.0.metadata.0.self_link": "",
                            "spec.0.template.0.metadata.0.uid": "",
                            "spec.0.template.0.spec.#": "1",
                            "spec.0.template.0.spec.0.active_deadline_seconds": "0",
                            "spec.0.template.0.spec.0.container.#": "1",
                            "spec.0.template.0.spec.0.container.0.args.#": "3",

一般来说,如果有人想要面试的编程问题,只需要求他们为此任务编写一个解析器:)
经过多次尝试编写一个没有 bug 的解析器,我在 terraform 代码中找到了一部分,也是最重要的部分。 一切似乎都运转良好

尝试三
terraform 提供程序是二进制文件,其中包含具有使用云 API 的所有资源和逻辑的代码。 每个云都有自己的提供者,Terraform 本身仅通过两个进程之间的 RPC 协议调用它们。
现在我决定通过 RPC 调用直接联系 terraform 提供商。 结果很漂亮,并且可以将 terraform 提供程序更改为较新的提供程序,并在不更改代码的情况下获得新功能。 事实证明,并非 tfstate 中的所有字段都应该在 tf 中,但是如何才能找到呢? 只需询问您的提供商即可。 然后,另一个组装正则表达式的递归色情开始了,在各个深度级别上搜索 tfstate 内的字段。

最后,我们得到了一个有用的 CLI 工具,它为所有 terraform 提供商提供了通用的基础设施,您可以轻松添加新的。 此外,添加资源只需要很少的代码。 加上各种好处,例如资源之间的连接。 当然,还有很多不同的问题,无法一一描述。
我将这种动物命名为 Terrafomer。

压轴

使用 Terrafomer,我们从两个云生成了 500-700 万行 tf + tfstate 代码。 我们只能通过 terraform 来获取遗留的东西并开始接触它们,就像在最好的基础设施中作为代码想法一样。 当您获取巨大的云并通过团队以 terraform 工作文件的形式接收它时,这真是太神奇了。 然后 grep/replace/git 等等。

我把它梳理出来并按顺序排列,得到许可。 周四 (02.05.19/XNUMX/XNUMX) 在 GitHub 上向所有人发布。 github.com/GoogleCloudPlatform/terraformer
已经收到 600 颗星,2 个添加对 openstack 和 kubernetes 支持的拉取请求。 良好的反馈。 总的来说,该项目对人们有用
我建议每个想要开始使用 Terraform 的人不要为此重写所有内容。
我很乐意拉取请求、问题、星星。

演示
Terraformer - 基础设施到代码

来源: habr.com

添加评论