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,執行“terraform refresh”,然後我們會得到完整的 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 - 基礎架構到程式碼

來源: www.habr.com

添加評論