Terraformer - Инфраструктура за кодиране

Terraformer - Инфраструктура за кодиране
Бих искал да ви разкажа за новия CLI инструмент, който написах за решаване на стар проблем.

проблем

Terraform отдавна е стандарт в Devops/Cloud/IT общността. Нещото е много удобно и полезно за работа с инфраструктура като код. В Terraform има много изкушения, както и много вилици, остри ножове и гребла.
С Terraform е много удобно да създавате нови неща и след това да ги управлявате, променяте или изтривате. Какво трябва да направят тези, които имат огромна инфраструктура в облака и не са създадени чрез Terraform? Пренаписването и повторното създаване на целия облак е някак скъпо и опасно.
Срещнах този проблем при 2 задачи, най-простият пример е, когато искате всичко да е в Git под формата на terraform файлове, но имате 250+ кофи и е много да ги пишете в terraform на ръка.
Има издаване от 2014 г. в терафом, който беше закрит през 2016 г. с надеждата да има внос.

Като цяло всичко е като на снимката само от дясно на ляво

Предупреждения: Авторът не живее половината си живот в Русия и пише малко на руски. Пазете се от правописни грешки.

Решения

1. Има готови и стари решения за AWS тераформиране. Когато се опитах да прекарам моите 250+ кофи през него, разбрах, че там всичко е лошо. AWS отдавна въвежда много нови опции, но тераформирането не знае за тях и като цяло е рубинено шаблонът изглежда оскъден. След 2 вечерта изпратих Заявка за изтегляне да добави още функции там и разбра, че такова решение изобщо не е подходящо.
Как работи тераформирането: взема данни от AWS SDK и генерира tf и tfstate чрез шаблон.
Тук има 3 проблема:
1. Винаги ще има забавяне в актуализациите
2. tf файловете понякога излизат повредени
3. tfstate се събира отделно от tf и не винаги се събира
По принцип е трудно да се получи резултат, в който `тераформен план` казва, че няма промени

2. `terraform import` е вградена команда в terraform. Как работи?
Пишете празен TF файл с името и типа на ресурса, след което стартирате `terraform import` и предавате ID на ресурса. terraform се свързва с доставчика, получава данните и прави tfstate файл.
Тук има 3 проблема:
1. Получаваме само tfstate файл и tf е празен, трябва да го напишете ръчно или да го конвертирате от tfstate
2. Може да работи само с един ресурс наведнъж и не поддържа всички ресурси. И какво да правя пак с 250+ кофи?
3. Трябва да знаете идентификационния номер на ресурсите - тоест трябва да го обвиете в код, който получава списъка с ресурси
Като цяло резултатът е частичен и не се мащабира добре

Моето решение

Изисквания:
1. Възможност за създаване на tf и tfstate файлове за ресурси. Например, изтеглете всички кофи/група за сигурност/балансиране на натоварването и този `terraform plan` върна, че няма промени
2. Имате нужда от 2 GCP + AWS облака
3. Глобално решение, което лесно се актуализира всеки път и не губи време за всеки ресурс за 3 дни работа
4. Направете го с отворен код - всеки има същия проблем

Езикът Go е причината, поради която го харесвам и има библиотека за създаване на HCL файлове, която се използва в terraform + много код в terraform, който може да бъде полезен

Път

Опитайте се първо
Започнах с проста версия. Свързване с облака чрез SDK за необходимия ресурс и преобразуването му в полета за terraform. Опитът умря незабавно в групата за сигурност, защото не ми харесаха 1.5 дни за конвертиране само на групата за сигурност (и има много ресурси). За дълго време и след това могат да се променят/добавят полета

Втори опит
Въз основа на описаната идея тук. Просто вземете и конвертирайте tfstate в tf. Всички данни са там и полетата са същите. Как да получите пълен tfstate за много ресурси?? Тук идва на помощ командата `terraform refresh`. terraform взема всички ресурси в tfstate и чрез ID извлича данни за тях и записва всичко в tfstate. Тоест, създайте празно 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",

Като цяло, ако някой иска програмен проблем за интервю, просто го помолете да напише парсер за тази задача :)
След много опити да напиша анализатор без грешки, намерих част от него в кода на terraform и то най-важната част. И изглеждаше, че всичко работи добре

Опит три
доставчиците на terraform са двоични файлове, които съдържат код с всички ресурси и логика за работа с облачния API. Всеки облак има свой собствен доставчик и самият terraform ги извиква само чрез своя RPC протокол между два процеса.
Сега реших да се свържа директно с доставчиците на terraform чрез RPC повиквания. Получи се прекрасно и направи възможно смяната на доставчиците на terraform с по-нови и получаването на нови функции без промяна на кода. Оказва се също, че не всички полета в tfstate трябва да са в tf, но как можете да разберете? Просто попитайте вашия доставчик за това. След това започна друга рекурсивна порнография на сглобяване на регулярни изрази, търсейки полета в tfstate на всички нива в дълбочина.

В крайна сметка получихме полезен CLI инструмент, който има обща инфраструктура за всички доставчици на terraform и можете лесно да добавите нова. Освен това добавянето на ресурси отнема малко код. Плюс всякакви екстри като връзки между ресурси. Разбира се, имаше много различни проблеми, които не могат да бъдат описани всички.
Нарекох животното Терафомер.

финал

Използвайки Terrafomer, генерирахме 500-700 хиляди реда tf + tfstate код от два облака. Успяхме да вземем наследени неща и да започнем да ги докосваме само чрез тераформа, както в най-добрата инфраструктура като идеи за код. Просто е магия, когато вземете огромен облак и го получите чрез екип под формата на тераформирани работни файлове. И след това grep/replace/git и така нататък.

Разресах го и го подредих, получих разрешение. Пуснат в GitHub за всички в четвъртък (02.05.19/XNUMX/XNUMX). github.com/GoogleCloudPlatform/terraformer
Вече получи 600 звезди, 2 заявки за изтегляне за добавяне на поддръжка за openstack и kubernetes. Добра обратна връзка. Като цяло проектът е полезен за хората
Съветвам всички, които искат да започнат работа с Terraform и да не пренаписват всичко за това.
Ще се радвам да изтегля заявки, проблеми, звезди.

демонстрация
Terraformer - Инфраструктура за кодиране

Източник: www.habr.com

Добавяне на нов коментар