- PVSM.RU - https://www.pvsm.ru -
Хотел бы рассказать про новый CLI tool который я написал для решения одной старой проблемы.
Terraform уже давно стал стандартом в Devops/Cloud/IT сообществе. Вещь очень удобная и полезная чтоб заниматся infrastructure as code. Есть много прелестей в Terraform а так же много вилок, острых ножей и граблей.
С Terraform очень удобно делать новые вещи и потом ими управлять, менять или удалять. А что делать тем у кого есть огромная инфраструктура в облаке и не создано через Terraform? Переписывать и пересоздавать все облако как то дорого и небезопасно.
Я сталкивался с такой проблемой на 2 работах, самый простой пример когда хочешь что все было в гите виде терраформ файлов, а у тебя 250+ бакетов и писать их для терраформа руками как то много.
Есть issue [1] еще с 2014 года в terrafom которую закрыли в 2016 с надеждой что будет import.
Вообщем все как на картинке только справа налево
Предупреждения: Автор пол жизни живет не в России и пишет на русском мало. Осторожно ошибки в орфографии.
1. Есть готовое и старое решения для AWS terraforming [2]. Когда я пытался через него получить мои 250+ бакетов то понял что там все плохо. AWS уже давно накидали много новых опций а terraforming про них не знает и вообще у него ruby темплет выглядят скудно [3]. После 2 вечером я послал Pull request [4] чтоб добавить больше возможностей туда и понял что такое решения не подходит вообще.
Как работает terraforming он берет с SDK AWS данные и генерирует 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 по ресурсам. Например скачать все бакеты/security group/load balancer и что `terraform plan` возвращал что нет изменений
2. Надо 2 облака GCP + AWS
3. Глобальное решения которое легко обновлять каждый раз и не тратить время на каждый ресурс по 3 дня работы
4. Сделать Open source — проблема у всех такая
Язык Go — потому я люблю, и на нем есть библиотека для создания HCL файлов которая используется в terraform + много кода в terraform который может быть полезный
Попытка первая
Начал простой вариант. Обращения в облако через SDK за нужным ресурсом и конвертирования его в поля для terraform. Попытка умерла сразу на security group потому что мне не понравилось 1.5 дня конвертировать только security group(а ресурсов много). Долго и потом поля могут менять/добавлятся
Попытка вторая
Основано на идеи описанной тут [5]. Просто взять и сконвертировать tfstate в tf. Все данные там есть и поля те же. Как получить полный tfstate для много ресурсов?? Тут на помощь пришла команда `terraform refresh`. terraform берет все ресурсы в tfstate и по ID вытаскивает по ним данные и пишет все в tfstate. То есть создать пустой tfstate только с именами и ID, запустить `terraform refresh` то получаем полные tfstate. Ура!
Теперь займемся рекурсивной порнографием написание конвертора для tfstate в tf. Для тех кто никогда не читал tfstate то это JSON, но особенный.
Вот его важная часть attributes
"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 — string
2. metadata — array размером 1 и в нем объект с полями который описан ниже
3. spec — hash размером 1 и в нем key,value
Короче веселый формат, все может быть в глубь тоже на несколько уровней
"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 provider — это бинарки в которых есть код со всеми ресурсами и логикой для работы с API облаков. У каждого облака есть свой provider и сам terraform только вызывает их через свой протокол RPC между двумя процессами.
Теперь я решил обращаться напрямую к terraform providers через RPC вызовы. Так вышло красиво и дало возможность менять terraform providers на более новые и получать новые возможность не меняя код. Еще оказалось не все поля в tfstate должны быть в tf, а как это узнать? Только спросить provider об этом. Потом началась еще одна рекурсивной порнографием по сборки регулярных выражений канитель с поиском полей внутри tfstate на всех уровнях в глубь.
В конце получилось полезный CLI tool у которого общая инфраструктура для всех terraform providers и можно легко добавить нового. Также добавления ресурсов занимает мало кода. Плюс всякие плюшки типа соединения между ресурсами. Конечно было много разных проблем которые все не описать.
Назвал зверушку Terrafomer.
Мы с помощью Terrafomer сгенерировали 500-700 тысяч строк кода tf + tfstate c двух облаках. Смогли взять легаси вещи и начать их трогать только через terraform как в лучших идеях infrastructure as code. Просто магия когда берешь огромное облако и получаешь через команду его в виде terraform файлов рабочих. А дальше grep/replace/git и так далее.
Вычесал и привел в порядок, получил разрешения. Выпустил на гитхаб для всех в четверг(02.05.19). github.com/GoogleCloudPlatform/terraformer [6]
Получил уже 600 звезд, 2 pull requests добавления поддержки openstack и kubernetes. Хорошие отзывы. Вообще проект полезный для людей
Советую всем кто хочет начать работать с Terraform и не переписывать все для этого.
Буду рад pull requests, issues, stars.
Автор: sergeylanz
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/open-source/316835
Ссылки в тексте:
[1] issue: https://github.com/hashicorp/terraform/issues/581
[2] terraforming: https://github.com/dtan4/terraforming
[3] темплет выглядят скудно: https://github.com/dtan4/terraforming/blob/master/lib/terraforming/template/tf/s3.erb
[4] Pull request: https://github.com/dtan4/terraforming/pull/396
[5] тут: https://github.com/hashicorp/terraform/issues/15608
[6] github.com/GoogleCloudPlatform/terraformer: https://github.com/GoogleCloudPlatform/terraformer
[7] Image: https://asciinema.org/a/243961
[8] Источник: https://habr.com/ru/post/450410/?utm_source=habrahabr&utm_medium=rss&utm_campaign=450410
Нажмите здесь для печати.