Описание инфраструктуры в Terraform на будущее. Антон Бабенко (2018г)

2tw-cxkjewlvus-otixblhw5i8a.jpeg

Многие знают и используют Terraform в повседневной работе, но для него до сих пор не сформировались лучшие практики. Каждой команде приходится изобретать свои подходы, методы.

Ваша инфраструктура почти наверняка начинается просто: несколько ресурсов + несколько разработчиков. Со временем она растёт во всевозможные стороны. Вы находите способы сгруппировать ресурсы в Terraform-модули, организовать код по папкам, и что здесь вообще может пойти не так? (известные последние слова)

Проходит время, и вы чувствуете, что ваша инфраструктура — это ваш новый питомец, но почему? Вас беспокоят необъяснимые изменения в инфраструктуре, вы боитесь прикасаться к инфраструктуре и коду — в итоге вы задерживаете новый функционал или снижаете качество…

После трёх лет управления на Github коллекцией community-модулей Terraform для AWS и долгосрочном поддержании Terraform в продакшене, Антон Бабенко готов поделиться своим опытом: как писать TF-модули, чтобы не было больно в будущем.

К концу доклада участники будут лучше знакомы с принципами управления ресурсами в Terraform, лучшими практиками, связанными с модулями в Terraform, и некоторыми принципами непрерывной интеграции, связанными с управлением инфраструктурой.

Disclaimer: Замечу что доклад этот датирован ноябрем 2018 года — прошло уже 2 года. Рассматриваемая в докладе версия Terraform 0.11 уже не поддерживается. За прошедшие 2 года вышло 2 новых релизов, в которых появилась масса новшеств, улучшений и изменений. Прошу на это обратить внимание и сверятся с документацией.

iijagbx-f7undi8xluvpbcwydfe.jpeg

Ссылки:

Меня зовут Антон Бабенко. Кто-то из вас наверняка использовал код, который я писал. Я сейчас буду об этом говорить с большей уверенностью, чем когда-либо, потому что у меня есть доступ к статистике.

Я занимаюсь Terraform и являюсь активным участником и контрибьютором в большом количестве open source проектов, связанных с Terraform и Amazon с 2015-го года.

Примерно с тех пор я написал достаточно кода, чтобы изложить это в интересном виде. И об этом я попробую сейчас рассказать.

Я буду рассказывать о тонкостях и о специфике работы с Terraform. Но на самом деле это не является предметом для HighLoad. И сейчас вы поймете почему.

Со временем я начал писать Terraform-модули. Пользователи писали вопросы, я их переписывал. Потом я написал разные утилиты для форматирования кода с помощью pre-commit hook и т. д.

Было много интересных проектов. Мне нравится заниматься кодогенерированием, потому что я люблю, чтобы компьютер делал все больше и больше работы за меня и за программиста, поэтому сейчас работаю над генератором Terraform-кода из визуальных диаграмм. Возможно, кто-то из вас их видел. Это красивые коробочки со стрелочками. И я считаю, что это здорово, если можно нажать кнопочку «Экспорт» и получить это все как код.

Я из Украины. Я живу много лет в Норвегии.

Также информация для этого доклада была собрана от людей, которые знают мое имя и находят меня в социальных сетях. У меня почти всегда один и тот же ник.

aeuqqgdhv8ltpk-fca6yet_yjrs.jpeg

https://github.com/terraform-aws-modules

https://registry.terraform.io/namespaces/terraform-aws-modules

Как я упомянул, я являюсь главным мейнтейнером Terraform AWS modules, который является одной из самых больших репозиторий на GitHub, где мы хостим модули для самых распространенных задач: VPC, Autoscaling, RDS.

jndoii1uc4wxvmid3r0ihprqehg.jpeg

И то, что вы слышали сейчас, это самое-самое базовое. Если вы сомневаетесь, что вы понимаете, что такое Terraform, то лучше проводить время где-нибудь в другом месте. Здесь будет много технических терминов. И уровень доклада я не постеснялся заявить самым максимальным. Это значит, что я могу рассказывать, используя все-все возможные термины без особого объяснения.

snzjqopf57sdh3xbg1scjtlglio.jpeg

Terraform появился в 2014-ом году как утилита, которая позволяла писать, планировать и управлять инфраструктурой как код. Ключевое понятие здесь «инфраструктура как код».

Вся документация, как я сказал, написана на https://www.terraform.io/. Я надеюсь, что большинство знают об этом сайте и прочитали документацию. Если так, то вы в нужном месте.

xakics1tj4tpdvo6wc_dvwtqujk.jpeg

Вот так выглядит обычный Terraform-конфигурационный файл, где мы сначала определяем какие-то переменные.

gb_ukhynarn21ns1qnoschte8hu.jpeg

В данном случае мы определяем «aws_region».

ghzukpgiaj-xf6kojy5hhsjgpzg.jpeg

Потом мы описываем, какие ресурсы мы хотим создать.

tc1qya9orxxitbh7oayrikjmdec.jpeg

Запускаем какие-то команды, в частности «terraform init» для того, чтобы загрузить зависимости, провайдеры.

vyscm-jajj1hzclil8410zgcinq.jpeg

И запускаем команду «terraform apply» для того, чтобы проверить соответствует ли указанная конфигурация тем ресурсам, которые создали. Т. к. мы ничего не создавали до этого, то Terraform предлагает нам создать эти ресурсы.

3oqd5hbfgckyehhnn9bsmmg3eyy.jpeg

Мы подтверждаем это. Таким образом мы создаем bucket, который называется seasnail.

3zmu9gkkebhpmzdjh3x6mnh1aes.jpeg

Есть также несколько похожих утилит. Многие из вас, кто пользуется Amazon, знают AWS CloudFormation или Google Cloud Deployment Manager, или Azure Resource Manager. У каждого из них есть своя какая-то реализация для управления ресурсами внутри каждого из этих public cloud провайдеров. Terraform особенно полезен в той связи, что он позволяет управлять более 100 провайдерами. (Подробнее на https://www.terraform.io/docs/providers/index.html)

jqmryymoyboylf6ekiwsj6ltswy.jpeg

Цели, которые преследовал Terraform с самого начала:


  • Terraform дает единый вид ресурсов.
  • Позволяет поддерживать все современные платформы.
  • И Terraform с самого начала задумывался как утилита, которая позволяет менять инфраструктуру безопасно и предсказуемо.

В 2014-ом году слово «предсказуемо» звучало очень необычно в данном контексте.

vbcau0-bgspkimtzfojtkqzzhtm.jpeg

Terraform является универсальной утилитой. Если у вас есть API, то можно управлять совершенно всем:


  • Можно использовать более 120 провайдеров для управления всем, к чему душа лежит.
  • Например, можно использовать Terraform для описания доступа к GitHub репозиториям.
  • Можно даже баги в Jira создавать и закрывать.
  • Можно управлять New Relic-метриками.
  • Можно даже файлы в dropbox создавать, если очень хочется.

Это все достигается с помощью Terraform-провайдеров, у которых открытый API, которые можно описать на Go.

94krhouw4glgd-1njpsqbnoefpu.jpeg

Допустим, мы начали использовать Terraform, прочитали какую-то документацию на сайте, посмотрели какое-то видео, начали писать main.tf, как я показывал на предыдущих слайдах.

hcg4cc-jwkoz3ol8kqzyqtfn1m8.jpeg

И у вас все классно, у вас получился файл, который создает VPC.

Если вы хотите создать VPC, то вы указываете примерно вот эти 12 строк. Описываете в каком регионе вы хотите создать, какой cidr_block IP-адресов использовать. И все.

icd_gwhkkwjkov9hefm-erz_3r4.jpeg

Естественно, постепенно проект будет расти.

s29dxk46snpyah4t_cvz8tgfmh4.jpeg

И вы будете добавлять туда кучу нового всего: ресурсы, источники данных, вы будете интегрироваться с новыми провайдерами, неожиданно вы захотите использовать Terraform для того, чтобы управлять пользователями в вашем GitHub-аккаунте и т. д. Вы можете захотеть использовать разные DNS-провайдеры, скрещивать все подряд. Terraform легко позволяет это делать.

q45m7k8k9tnoxry0ovijmanlqvg.jpeg

Рассмотрим следующим пример.

0jb65wcde3cctjb67hvodiu0gum.jpeg

Вы постепенно добавляете internet_gateway, потому что вы хотите, чтобы ресурсы из вашего VPC имели доступ в интернет. Это хорошая идея.

kgrnmjfeucslbkuku0_tyyiusee.jpeg

В итоге получается вот такой main.tf:

baqgtsdzlnlczrph5ykeq9jxbva.jpeg

Это верхняя часть main.tf.

xbeztr5z2gle8a0edbg523irmcu.jpeg

Это нижняя часть main.tf.

Потом вы добавляете subnet. К тому моменту, когда вы захотите добавить NAT gateways, routes, routing tables и кучу других subnets, у вас будет не 38 строк, а примерно 200–300 строк.

zyyn4g3ylyabmzplnabehqemveo.jpeg

Т. е. ваш main.tf файл постепенно растет. И довольно часто люди складывают все в один файл. В main.tf появляется 10–20 Kb. Представьте, что 10–20 Kb — это текстовый контент. И всё со всем связано. С этим работать постепенно становится сложно. 10–20 Kb — это хороший user case, бывает и больше. И не всегда люди считают, что это плохо.

Как и в обычном программировании, т. е. не инфраструктура как код, мы привыкли использовать кучу разных классов, пакетов, модулей, группировки. Terraform позволяет делать примерно тоже самое.

tbfasbbywrgq_gvagtdrp1oqb0w.jpeg


  • Код растет.
  • Зависимости между ресурсами тоже растут.

wexcpfag3mv2pqbb2syy67vm9d8.jpeg

И у нас возникает большая-большая нужда. Мы понимаем, что так жить мы дальше не можем. У нас код становится необъятным. 10–20 Kb — это, конечно, не очень необъятный, но это мы говорим только о network stack, т. е. вы добавили только сетевые ресурсы. Мы не говорим еще об Application Load Balancer, deployment ES cluster, Kubernetes и т. д., куда еще легко можно вплести 100 Kb. Если вы все это напишите, то вы очень скоро узнаете, что Terraform предоставляет Terraform-модули.

60olo5ubqpfyon0memxzp3axl2q.jpeg

Terraform-модули — это самодостаточная Terraform-конфигурация, которая управляется как группа. Это все, что надо знать о Terraform-модулях. Они никакие не умные, они не позволяют делать вам какие-то сложные подключения в зависимости от чего-то. Это все ложится на плечи разработчиков. Т. е. это просто какая-то Terraform-конфигурация, которую вы уже написали. И можно просто ее вызывать как группу.

zdi7nfmycgyzitttjvtzzt7ttfa.jpeg

Таким образом мы пытаемся понять, как мы будем оптимизировать наши 10–20–30 Kb кода. Мы постепенно понимаем, что надо использовать какие-то модули.

Первый тип модулей, который встречается, это ресурсные модули. Они не понимают, о чем ваша инфраструктура, о чем ваш бизнес, где и какие условия. Это именно те модули, которые я вместе с open source сообществом администрируем, и которые мы выдвигаем, как самый начальный building blocks для вашей инфраструктуры.

e9xjpuvhjuvaytd7hxdyltflphw.jpeg

Пример ресурсного модуля.

sysgksv9ncltagsxxw9qmz5ebk8.jpeg

Когда мы вызываем ресурсный модуль, мы указываем с какого пути мы должны загрузить его содержимое.

bbt_fildwwaelufyp63cv7rlf7s.jpeg

Мы указываем какой версии мы хотим загрузить.

rfjm_mqowc0f9alnrrfzfqbrdgm.jpeg

Мы передаем кучу аргументов туда. И все. Это все, что нам надо знать, когда мы используем этот модуль.

ee2ovcirujl0gqul263_ejzzqfg.jpeg

Многие думают, что если использовать последнюю версию, то все будет стабильно. Но нет. Инфраструктура должна быть версионной, мы четко должны ответить, какой версии была задеплоена та или иная компонента.

rwcy5djzmkauwvgbrjmmwluwntc.jpeg

Перед вами код, который находится внутри этого модуля. Модуль security-group. Здесь скролл идет до 640-ой строчки. Создание security-croup ресурса в Amazon во всевозможной конфигурации — это очень нетривиальная задача. Недостаточно просто создать security-group и сказать, какие правила ей передавать. Это было бы очень просто. Внутри Amazon есть миллион разных ограничений. Например, если вы используете VPC endpoint, prefix list, различные API и пытается это всё со всем скрестить, то Terraform не позволяет вам это сделать. И Amazon API тоже не позволяет это. Поэтому надо спрятать эту всю страшную логику в модуль и пользователю выдавать код, который выглядит только вот так.

e9xjpuvhjuvaytd7hxdyltflphw.jpeg

Пользователю не надо знать, как внутри оно сделано.

ng9hkvm-dswptfc1dwcv9-elega.jpeg

Второй тип модулей, который состоит из ресурсных модулей, уже решает задачи, которые более применимы для вашего бизнеса. Часто это место, которое является расширением для Terraform и задает какие-то жесткие значения для тегов, для стандартов компании. Также там можно добавлять функционал, который Terraform не позволяет сейчас использовать. Это именно сейчас. Сейчас версия 0.11, которая вот-вот отойдет в прошлое. Но все равно препроцессоры, jsonnet, cookiecutter и куча других вещей являются тем вспомогательным механизмом, который надо использовать для полноценной работы.

Дальше я покажу некоторые примеры из этого.

fdianje604p1docozzx-wpx6vl0.jpeg

Инфраструктурный модуль вызывается точно таким же способом.

fsqg-kkzcw6tnh-oe_ixms_d-gc.jpeg

Указывается источник, откуда загрузить контент.

dhdodzoi6mfxisvy8rvxutcxtq8.jpeg

Передается куча значений, которые передаются в этот модуль.

-dg85ubcbxxaatueghjnyzeqksq.jpeg

Далее внутри этого модуля вызывается куча ресурсных модулей для создания VPC или Application Load Balancer, или для создания security-group или для Elastic Container Service кластера.

4bt4jgwk3vyiixg-grlq-awka8a.jpeg

Есть два типа модулей. Это важно понимать, потому что большинство информации, которую я сгруппировал в этом докладе, не написана в документации.

И документация в Terraform прямо сейчас достаточно проблематичная, потому что она просто говорит, что есть такие фичи, вы можете их использовать. Но она не говорит, как эти фичи использовать, почему так лучше использовать. Поэтому очень большое количество людей пишут что-то, с чем потом нельзя жить.

ewcn1nrdqgqfj7m3hhsnzv6zqts.jpeg

Давайте дальше посмотрим, как писать эти модули. Потом посмотрим, как их вызывать и как работать с кодом.

pr2jb3czf91y1t1vng6ofpaf7bi.jpeg

Terraform Registry — https://registry.terraform.io/

Совет № 0 — это не писать ресурсные модули. Большинство этих модулей уже написано за вас. Как я говорил, они open source, они не содержат никакой вашей бизнес-логики, в них нет захардкоженных значений для IP-адресов, паролей и т. д. Модуль является очень flexible. И он уже, скорее всего, написан. Для ресурсов от Amazon модулей много. Около 650. И большинство из них хорошего качества.

knqjfjut6jti5b5etoz6yvffzt4.jpeg

На данном примере к вам пришел кто-то и сказал: «Я хочу иметь возможность управлять базой данных. Создай модуль, чтобы я мог создавать базу данных». Человек не знает подробностей реализации ни Amazon, ни Terraform. Он просто говорит: «Я хочу управлять MSSQL». Т. е. мы подразумеваем, что он будет вызывать наш модуль, передаст туда тип движка, укажет time-зону.

_6nz7foy542gt9osvj8k3lozhqo.jpeg

И человек не должен знать, что мы внутри этого модуля будем создавать два разных ресурса: один для MSSQL, второй для всего остального только потому, что в Terraform 0.11 нельзя указывать значения time-зоны необязательным.

rzavkj5to-pnpoiiqrx1byss88q.jpeg

И на выходе из этого модуля человек будет иметь возможность просто получать адрес. Он не будет знать с какой базы данных, с какого ресурса мы внутри это все создаем. Это очень важный элемент скрытия. И это применимо не только для тех модулей, которые находятся в public в open source, а также для тех модулей, которые вы будете писать внутри своих проектов, команд.

2lef7-3v4hrjm-oayect6zv3mba.jpeg

Вот это второй аргумент, который является довольно важным, если вы используете Terraform какое-то время. У вас есть репозиторий, в котором вы складываете все свои Terraform-модули для вашей компании. И вполне нормально, что со временем этот проект вырастет до размера одного-двух мегабайт. Это нормально.

Но проблема заключается в том, как Terraform вызывает эти модули. Например, если вы будете вызывать модуль для создания каждого индивидуального пользователя, то Terraform сначала будет загружать весь репозиторий, а потом переходить в папку, где находятся конкретно этот модуль. Таким образом вы будете каждый раз загружать по одному мегабайту. Если вы управляете 100 или 200 пользователями, то вы загрузите 100 или 200 мегабайт, а потом уже перейдете в ту папку. Таким образом, естественно, вы не хотите каждый раз, когда нажимаете «Terraform init» загружать кучу всего.

ieol9gwxs3nadxpouxcd7uujce0.jpeg

https://github.com/mbtproject/mbt

Есть два решения этой проблемы. Первое заключается в том, чтобы использовать относительные пути. Таким образом вы в коде указываете, что папка локальная (./). И перед тем, как что-то запускать, вы делаете Git clone этого репозитория локально. Таким образом вы делаете это один раз.

Есть, конечно, куча downsides. Например, что нельзя использовать versioning. И с этим иногда сложно жить.

Второе решение. Если у вас много подмодулей и у вас есть уже какой-то устаканенный pipeline, то есть проект MBT, который позволяет собирать из монорепозитория много разных пакетов и загружать их на S3. Это очень хороший способ. Таким образом файл iam-user-1.0.0.zip будет весить всего лишь 1 Kb, потому что код для создания этого ресурса очень маленький. И это будет намного быстрее работать.

y2uwvylxkv4ty4vfjc5drnkyh0o.jpeg

Поговорим о том, что нельзя использовать в модулях.

g58wo79_b9hchqbyzwu_e8rjknw.jpeg

Почему в модулях это зло? Самая страшная вещь — это assume user. Assume user — это такой вариант аутентификации в провайдер, который могут использовать разные люди. Например, мы все будем ассюмить роль. Это значит, что Terraform будет принимать эту роль. И потом с этой ролью будет выполнять остальные действия.

jrfz43qss3qr7qvtpvd_lijuub0.jpeg

И зло заключается в том, что если Вася любит подключаться к Amazon одним способом, например, используя по умолчанию переменное окружение, а Петя любит использовать свой shared key, который у него находится в секретном месте, то в Terraform нельзя указывать и то и другое. И для того, чтобы они не испытывали страданий, не надо этот блок указывать в модуле. Это надо указывать уровнем выше. Т. е. у нас есть ресурсный модуль, инфраструктурный модуль и композиция сверху. И где-нибудь повыше это надо указывать.

favjmtuheebxgdgkcoi_ht9lnqa.jpeg

Второе зло заключается в provisioner. Здесь зло не настолько тривиальное, потому что если пишите код и для вас он работает, то вы можете подумать, что если он работает, то зачем менять.

xgoem0divo_4wv3ydyehletcrxe.jpeg

Зло заключается в том, что этот provisioner вы не всегда контролируете, когда он конкретно будет запускаться, во-первых. И, во-вторых, вы не контролируете, что значит aws ec2, т. е. мы говорим сейчас про Linux или про Windows. Таким образом, вы не можете писать что-то, что будет работать одинаково в разных операционных системах или для разных user cases.

vnzhw7ksll5zdvzvkt469e6cfry.jpeg

Самый распространенный пример, который в том числе указан в официальной документации, это то, что если вы пишите aws_instance, указываете кучу аргументов, то ничего плохого в этом нет, если вы укажете там и provisioner «local-exec» и запустите свой ansible-playbook.

sobgbxaaijp_shkqzzffzg3yh5w.jpeg

На самом деле — да, ничего плохого в этом нет. Но буквально скоро вы осознаете, что вот эта штука local-exec не существует, например, в launch_configuration.

qpdohy-b5xgyfwm1duf6lbvzawk.jpeg

И когда вы используете launch_configuration, и вы хотите из одного instance создать autoscaling group, то в launch_configuration нет понятия «provisioner». Там есть понятие «user data».

6nlf2zfha8ilys3fegx1gmbjeuu.jpeg

Поэтому более универсальным решением является использование user data. И будет запускаться либо на самом instance, когда instance включится, либо в этом же user data, когда autoscaling group будет использовать этот launch_configuration.

z9qesscbuddebiskaywwebjwr2i.jpeg

Если все-таки есть желание запустить provisioner, потому что он является склеивающим компонентом, когда один ресурс будет создан и в этот момент надо запустить свой provisioner, свою команду. Таких ситуаций очень много.

И самый правильный ресурс для этого называется null_resource. Null_resource — это фиктивный ресурс, который на самом деле не создается никогда. Он ничего не трогает, нет API, нет autoscaling. Но он позволяет регулировать, когда запускать команду. В данном случае запускается команда во время создания.

c8h4pv7eoiwgut-me5gfvofu2qc.jpeg

Ссылка http://bit.ly/common-traits-in-terraform-modules

Есть несколько признаков. Я не буду останавливаться на всех признаках очень детально. Есть статья об этом. Но если вы работали с Terraform или использовали чужие модули, то вы часто замечали, что многие модули, как и большую часть кода в open source, люди пишут для своих каких-то нужд. Человек его написал, решил свою задачу. Заколбасил его в GitHub, пускай живет. Он будет жить, но если там нет никакой документации и примеров, то никто им пользоваться не будет. И если там нет функционала, который позволяет решать чуть больше, чем его конкретную задачу, то им тоже никто не будет пользоваться. Есть очень много способов потерять пользователей.

Если вы хотите написать что-то, чтобы люди этим пользовались, то я рекомендую следовать этим признакам.

Это:


  • Документация и примеры.
  • Полный функционал.
  • Разумные значения по умолчанию.
  • Чистый код.
  • Тесты.

Тесты — это отдельная ситуация, потому что их довольно сложно написать. Я больше верю в документацию и в примеры.

nkdww643y_vuwqoqhps0clwhagu.jpeg

Итак, мы посмотрели, как писать модули. Есть два аргумента. Первый, который наиболее важный, это не пиши, если можешь, т. к. кучу-куча людей уже сделали эти задачи до вас. И второй, если все-таки решился, то провайдеры в модулях и provisioner старайся не использовать.

Это серая часть документации. Вы можете сейчас подумать: «Что-то непонятно. Не убедил». Но посмотрим через полгода.

qmfdji8-e4kfz34fyg8qhisxgmo.jpeg

Теперь поговорим о том, как вызывать эти модули.

Мы понимаем, что со временем наш код растет. У нас уже не один файл, у нас уже 20 файлов. Все они лежат в одной папке. Или, может, в пяти папках. Может быть, мы начинаем их как-то разбивать по регионам, по каким-то компонентам. Потом мы понимаем, что теперь у нас какие-то зачатки синхронизации, оркестрации должны возникать. Т. е. должны понять, что нам делать, если мы поменяли сетевые ресурсы, что нам делать с остальными нашими ресурсами, как вызывать эти зависимости и т. д.

0jq0ld8hoynv-pmfk-omdgfdtzm.jpegЕсть две крайности. Первая крайность — это все в одном. У нас есть один мастер-файл. До поры до времени это был официальная best practice на сайте Terraform.

Но сейчас это написано как deprecated и убрано. Со временем Terraform-сообщество поняло, что это далеко не best practice, потому что люди начинают использовать проект в разных видах. И есть проблемы. Например, когда мы указываем все зависимости в одном месте. Бывает ситуации, когда мы нажимаем «Terraform plan» и пока Terraform обновит состояния всех ресурсов, может пройти куча времени.

Куча времени — это, например, 5 минут. Для кого-то это куча времени. Я видел случаи, когда это занимало 15 минут. 15 минут AWS API дергался для того, чтобы понять, что со состоянием каждого ресурса. Это очень большая область.

И, естественно, появится связанная проблема, когда вы захотите поменять что-то в одном месте, потом подождали 15 минут, а оно вам выдало полотно каких-то изменений. Вы плюнули, написали «Yes», и что-то пошло не так. Это вполне реальный пример. Terraform не старается вас отгородить от проблем. Т. е. пишите, что хотите. Будут проблемы — ваши проблемы. Пока Terraform 0.11 не старается вам помочь никак. В 0.12 есть определенные интересные места, которые позволяют вам сказать: «Вася, ты действительно этого хочешь, можешь одумаешься?».

b63xwy6voucginof_r4dzjr0mzu.jpeg

Второй способ заключается в уменьшение этой области, т. е. можно меньше связывать вызовы одного места из другого места.

Единственная проблема в том, что нужно писать больше кода, т. е. нужно описывать переменные в большом количестве файлов, обновлять это. Кому-то это не нравится. Для меня это нормально. А некоторые думают: «Зачем это писать в разных местах, я это все в одном месте заколбасю». Можно и так, но это вторая крайность.

znage4dxnwwzj1xzulmwe8p8qxs.jpeg

У кого это все живет в одном месте? Один, два, три человека, т. е. кто-то использует.

А кто вызывает один конкретно компонент, один блок или один инфраструктурный модуль? Человек пять-семь. Это здорово.

l5zm91fcgzbe-tqpn33nfrt7z3y.jpeg

Самый частый ответ — это где-то посередине. Если проект большой, то у вас часто будет ситуация, когда ни то решение не годится и там не все получается, поэтому у вас получается смесь. В этом ничего плохого нет, лишь бы вы понимали, что есть преимущество и у того, и у того.

gmiwkzfrx95ol9cxz9_4ww_toyi.jpeg

Если изменилось что-то в stack VPC и вы захотели применить эти изменения EC2, т. е. вы захотели обновить autoscaling group, потому что у вас появилась новая subnet, то такого рода зависимости я называю оркестрацией. Есть какие-то решения: кто как использует?

Я могу подсказать, какие есть решения. Можно использовать Terraform для того, чтобы делать магию, а можно использовать make-файлы для использования Terraform. И смотреть, если там что-то поменялось, можно тут запустить.

sr-kmxnmb4zz1mlv4kqhpqv8ryg.jpeg

Как вам такое решение? Кто-то верит, что это классное решение? Я вижу улыбку, видать сомнения закрались.

vapcm5d_yfdcoe-92vdo_9edzrc.jpeg

Конечно, не повторяйте это дома. Terraform никогда не был создан для того, чтобы запускаться из Terraform.

Мне на одном докладе сказали: «Нет, это не будет работать». Дело в том, что оно и не должно работать. Хоть оно и выглядит так эффектно, когда ты можешь из Terraform запустить Terraform, а там еще Terraform, но не надо так делать. Terraform должен всегда запускаться очень просто.

p-q0ehfr7isrtjsqcfduwbqdcwq.jpeg

https://github.com/gruntwork-io/terragrunt/

Если у вас есть нужна в оркестрации вызовов, когда поменялось что-то в одном месте, то есть Terragrunt.

Terragrunt — это утилита, это надстройка над Terraform, которая позволяет координировать и оркестрировать вызовы инфраструктурных модулей.

k-vntqigsuuxbbodrj4xs9cdt14.jpeg

Типичный Terraform-конфигурационный файл выглядит вот так.

rwhguxr-lveylz6ajruf_hzoifg.jpeg

Вы указываете, какой конкретно модуль вы хотите вызвать.

czakzhlfb91mnivtw-ooy5l_shk.jpeg

Какие у модуля есть зависимости.

6zpnfmbzbpynmksedmikhvd7d5q.jpeg

И какие аргументы этот модуль принимает. Это все, что нужно знать о Terragrunt.

Документация там есть, 1 700 звездочек на GitHub тоже есть. Но в большинстве случаев это то, что надо знать. И это очень легко вживить в компании, которые только начали работать с Terraform.

kbiplrk5axpgvd19ijp88lpdhvg.jpeg

Таким образом, оркестрация — это Terragrunt. Другие варианты есть.

ghfovvigpdzuyd06w92k7uz7tlo.jpeg

Теперь давайте поговорим, как работать с кодом.

Если у вас есть необходимость добавить новые фичи в код в большинстве случаев это легко. Вы пишите новый ресурс, тут все просто.

zk4uedcbybb3n6dlp73wq9sbofw.jpeg

Если у вас есть какой-то ресурс, который вы создали заранее, например, вы про Terraform узнали после того, как вы открыли AWS-аккаунт и хотите использовать те ресурсы, которые у вас уже есть, то будет уместно расширить свой модуль таким образом, чтобы он поддерживал использование существующих ресурсов.

afiemfnpzj5gttdhkhyr0duadmi.jpeg

И поддерживал создание новых ресурсов, используя ресурс block.

_i6it1xinm2pfkaaegcfkjlva5k.jpeg

На выходе мы всегда возвращаем output id в зависимости оттого, что было использовано.

82t-byxcxv9u43yupotfl38fdtm.jpeg

Вторая очень существенная проблема в Terraform 0.11 — это работа со списками.

qlxv8tp2ghpdp4fkjqkxtlpgda0.jpeg

Сложность заключается в том, что если мы имеем такой список users.

3qzigkjz6ribbuioz8shmfuiddq.jpeg

И когда мы создаем этих users, используя block resource, то все проходит нормально. Мы проходим по всему списку, создаем каждому файлик. Все нормально. И потом, например, user3, который по середине, должен быть убран отсюда, то все ресурсы, которые были созданы после него, они будут пересоздаваться, потому что индекс изменится.

3fjbvhgo2uo67gxejcw6tkcl1ww.jpeg

Работа со списками в stateful-окружении. Что такое stateful-окружение? Это та ситуация, когда возникает новое значение при создании этого ресурса. Например, AWS Access Key или AWS Secret Key, т. е. когда мы создаем user«а, нам приходит новый Access или Secret Key. И каждый раз, когда мы будем удалять какого-то user«а, у этого user«а будет новый ключ. Но это не по фэншуй, потому что user не захочет с нами дружить, если мы будем каждый раз создавать нового user«а для него, когда кто-то покидает команду.

hfnlbsliqglglp8_nwxcsmoes84.jpeg

Решение такое. Это код, написанный на Jsonnet. Jsonnet — Это язык создания шаблонов от Google.

4zrowd8rzfwcdhoxr6wwdaftto8.jpeg

Это команда позволяет принять этот шаблон и на выходе он возвращает json-файл, который сделан по вашему шаблону.

giyyqovsjm8c2pxkjj-rrkxbj_4.jpeg

Шаблон выглядит вот так.

Terraform позволяет работать и с HCL, и с Json одинаково, поэтому если у вас есть возможность генерировать Json, то вы можете его подсунуть в Terraform. Файл с расширением .tf.json будет успешно загружен.

e8glqzllxtx97l3_0skunymdpri.jpeg

И потом мы работаем с этим как обычно: terraform init, terramorm apply. И мы создаем двух user«ов.

Теперь нам не страшно, если кто-то покинет команду. Мы просто отредактируем json-файл. Вася Пупкин ушел, Петя Пяточкин остался. Петя Пяточкин не получит новый ключ.

j71fpiuhigyvfyyis0tctlbzsgy.jpeg

Интеграция Terraform с другими средствами, по сути, не является задачей Terraform. Terraform создавался как платформа для создания ресурсов и все. И все, что подходит потом — это не забота Terraform. И не надо туда вплетать его. Есть Ansible, который делает все, что надо.

Но возникают ситуации, когда мы хотим дополнить Terraform и вызвать какую-то команду после того, как что-то выполнилось.

Первый способ. Мы создаем output, где мы пишем эту команду.

jn3oslg36mjm9hgr8u9wmnp6yxe.jpeg

А потом эту команду вызываем из shell terraform output и указываем это значение, которое мы хотим. Таким образом исполняется команда со всеми подставленными значениями. Это очень удобно.

mem9pe2ke-x90lqy-n0lw-4zrba.jpeg

Второй способ. Это использование null_resource в зависимости от изменений в нашей инфраструктуре. Мы можем вызывать тот же local-exeс, как только изменится ID какого-то ресурса.

quexmb8nhigodzmejigizel3ufk.jpeg

Естественно, это все гладко на бумаге, потому что Amazon как и все остальные public-провайдеры имеет кучу своих edge cases.

Самый распространенный edge cases заключается в том, что, когда вы открыли AWS-аккаунт, важно, какие вы регионы используете; включена ли эта фича там; может быть, вы его открыли после декабря 2013-го года; может быть, вы используете дефолт в VPC и т. д. Есть много ограничений. И Amazon разбросал их по всей документации.

aczmdo_wyfqi_njlucu-cm9uesy.jpeg

Есть несколько вещей, которые я рекомендую избегать.

Для начала избегайте всех несекретных аргументов внутри Terraform plan или Terraform CLI. Все это можно сложить либо в tfvars-файл, либо в переменное окружение.

Но не надо запоминать всю эту магическую команду. Terraform plan — var и понеслась. Первая переменная — var, вторая переменная — var, третья, четвертая. Самый важный принцип инфраструктуры как код, который я чаще всего использую, это то, что, просто взглянув на код, я должен прекрасно понимать, что там задеплоено, в каком состоя

© Habrahabr.ru