[Перевод] Перешел с Terraform на CloudFormation — и пожалел

Представлять инфраструктуру в виде кода в повторяемом текстовом формате — простая лучшая практика для систем, с которой не нужно мышевозить. За этой практикой закрепилось название — Infrastructure as Code, и пока что для ее осуществления, особенно в AWS, есть два популярных инструмента: Terraform и CloudFormation.

fff_rw-n0dk_n_l6qxrxkp_-h9i.png
Сравниваю опыт работы с Terraform и CloudFormation

До прихода в Twitch (он же Amazon Jr.) я трудился в одном стартапе и года три использовал Terraform. На новом месте я тоже вовсю использовал Terraform, а потом компания продавила переход на все а-ля Amazon, включая CloudFormation. Я усердно разрабатывал лучшие практики и для того, и для другого, и оба инструмента использовал в очень сложных рабочих процессах в масштабах организации. Позднее, вдумчиво взвесив последствия перехода с Terraform на CloudFormation, я убедился, что Terraform, наверное, — лучший выбор для организации.


Terraform Ужасный


Бета-версия ПО

У Terraform еще даже не вышла версия 1.0, и это — веская причина им не пользоваться. С тех пор, как я сам его впервые опробовал, он сильно изменился, но тогда еще terraform apply часто ломался после нескольких обновлений или просто через пару лет эксплуатации. Я бы сказал, что «сейчас-то все по-другому», но… так вроде все говорят, нет? Есть изменения, несовместимые с предыдущими версиями, хотя они уместны, и даже чувство такое, что синтаксис и абстракции хранилищ ресурсов теперь что надо. Инструмент как будто правда стал лучше, но… :-0

С другой стороны, AWS хорошо постаралась, поддерживая совместимость с предыдущими версиями. Все, наверное, потому, что их сервисы часто хорошенько тестируют внутри организации и лишь потом, переименовав, публикуют. Так что «хорошо постарались» это еще слабо сказано. Поддерживать совместимость с предыдущими версиями API для такой многовариантной и сложной системы, как AWS, невероятно тяжело. Любой, кому приходилось поддерживать общедоступные API, используемые так же широко, должен понимать, как трудно это делать на протяжении стольких лет. А вот поведение CloudFormation на моей памяти ни разу с годами не изменилось.


Знакомься, нога… это пуля

Насколько я знаю, удалить ресурс постороннего стека CloudFormation из своего стека CF невозможно. Примерно так же дело обстоит и с Terraform. Он позволяет импортировать существующие ресурсы в свой стек. Функция, можно сказать, потрясающая, но с большой силой приходит и большая ответственность. Стоит только занести ресурс в стек и, пока ты работаешь со своим стеком, удалить или изменить этот ресурс нельзя. Однажды это аукнулось. Как-то на сайте Twitch кто-то, не замышляя ничего дурного, случайно импортировал чью-то группу безопасности AWS в свой собственный стек Terraform. Ввел несколько команд и… группа безопасности (вместе со входящим трафиком) исчезла.


Terraform Великий


Восстановление из неполных состояний

Иногда CloudFormation не может полностью перейти из одного состояния в другое. При этом он постарается вернуться к предыдущему. Жаль, это не всегда осуществимо. Отлаживать потом то, что получилось, бывает страшноватенько — никогда не знаешь, обрадуется ли CloudFormation, что его взламывают — пусть и для починки. А получится или нет вернуться к предыдущему состоянию, он толком определять не умеет и по умолчанию часами висит в ожидании чуда.

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


Более ясные изменения в состояния документа


«Ладно, балансировщик нагрузки, ты меняешься. Но как?»

—обеспокоенный инженер, готовый нажать кнопку «принять».

Иногда мне нужно проделать кое-какие манипуляции с балансировщиком нагрузки в стеке CloudFormation — например, добавить номер порта или изменить группу безопасности. ClouFormation изменения отображает слабо. Я же, как на иголках, раз по десять перепроверяю файл yaml, чтобы убедиться, что ничего нужного не стер, а лишнего — не добавил.

Terraform в этом плане куда прозрачнее. Порой он даже слишком прозрачен (читай: достает). К счастью, в последнюю версию включили улучшенное отображение изменений — теперь точно видно, что изменяется.


Гибкость


Пишите ПО от обратного.

Говоря прямо, самая важная отличительная черта долгоживущего ПО — это способность адаптироваться к изменениям. Любое ПО пишите от обратного. Я вот чаще всего прокалывался на том, что брал «простенький» сервис, а потом принимался впихивать все в единый стек CloudFormation или Terraform. И конечно же, спустя месяцы вскрывалось, что я все понял не так, и сервис-то на самом деле не простой! И вот мне нужно неким образом разбить большой стек на малые составляющие. Когда работаешь с CloudFormation, сделать это возможно, только предварительно воссоздав существующий стек, а этого я, со своими БД, не делаю. Terraform же позволял препарировать стек и расчленить его на более понятные меньшие части.


Модули в git

Делиться кодом Terraform между многочисленными стеками гораздо проще, чем кодом CloudFormation. С Terraform можно поместить код в репозиторий git и обращаться к нему, используя семантический контроль версий. Любой, у кого есть доступ в этот репозиторий, может заново использовать общий код. Эквивалент от CloudFormation — S3, но у него нет тех же преимуществ, и нет ни одной причины, по которой нам вообще стоит отказаться от git в пользу S3.

Организация росла и способность делиться общими стеками достигла критического уровня. С Terraform все это получается легко и естественно, тогда как CloudFormation заставит вас попрыгать через кольца, прежде чем у вас заработает нечто подобное.


Operations as code


«Заскриптуем и ладно».

—инженер за 3 года до того, как изобрести велосипед Terraform.

Когда речь о разработке ПО, то Go или программа на Java — это не просто код.

qrpfecwuy-rwjaj48w68nzl0asq.png
Code as Code

Есть ведь еще инфраструктура, на которой она работает.

nmm89e9lu99otghnv73ta7bdqh8.png
Infrastructure as Code

Но откуда она там? Как ее мониторить? Где обитает ваш код? Нужно ли разработчикам разрешение на доступ?

hzesqsiuved-xhcccghgjoraxsi.png
Operations as Code


Быть разработчиком ПО — это вам не просто код писать.

Не AWS единым: вы наверняка пользуетесь услугами других поставщиков. SignalFx, PagerDuty или Github. Может быть, у вас есть внутренний сервер Jenkins для CI/CD или внутренняя панель управления Grafana для мониторинга. Infra as Code выбирают по разным причинам, и любая одинаково важна для всего, связанного с ПО.

Когда я работал в Twitch, мы ускоряли сервисы внутри смешанных встроенных систем и систем AWS Amazon’а. Мы штамповали и поддерживали множество микросервисов, увеличивая эксплуатационные издержки. Обсуждения проходили примерно в таком ключе:


  • Я: Блин, многовато телодвижений для разгона одного микросервиса. Мне вот эту фигню придется использовать, чтобы создать AWS аккаунт (мы шли к 2 аккаунтам на микросервис), потом эту — для настройки оповещений, еще эту — для репозитория кода, и эту — для списка адресов электронной почты, ну и вот эту…
  • Лид: Заскриптуем и ладно.
  • Я: Лады, но сам скрипт изменится. Нужен будет способ, как проверить, что все эти встроенные штуковины amazon’а имеют актуальное состояние.
  • Лид: Звучит неплохо. И для это скрипт напишем.
  • Я: Отлично! А скрипту наверняка еще надо будет задать параметры. Примет он их?
  • Лид: Да примет, куда денется!
  • Я: Процесс может измениться, потеряется обратная совместимость. Потребуется какой-нибудь семантически контроль версий.
  • Лид: Отличная идея!
  • Я: Инструменты можно изменить вручную, внутри пользовательского интерфейса. Нам потребуется способ, как это проверять и исправлять.

…3 года спустя:


  • Лид: И получился у нас terraform.

Мораль басни такова: даже если вы по уши во всем amazon’овском, вы все равно пользуетесь чем-нибудь не от AWS, и у этих сервисов есть состояние, которое использует язык для конфигурации, чтобы это состояние синхронизировать.


CloudFormation lambda vs git-модули terraform

lambda — это решение CloudFormation для вопроса пользовательской логики. С помощью lambda можно создавать макросы или пользовательский ресурс. Такой подход представляет дополнительные сложности, которых нет в семантическом контроле версий модулей git у Terraform. Для меня самой насущной проблемой стало управление разрешениями для всех этих пользовательских lambda (а это десятки аккаунтов AWS). Другой по важности стала проблема типа «что было раньше — курица или яйцо?»: она была связана с кодом lambda. Сама эта функция — инфраструктура и код, и она сама нуждается в мониторинге и обновлениях. Последним гвоздем в гроб стала трудность в семантическом обновлении изменений кода lambda; еще нужно было сделать так, чтобы действия стека без прямой команды не менялись между запусками.

Помню, как-то захотелось мне создать канареечный деплой для среды Elastic Beanstalk с классическим балансировщиком нагрузки. Проще всего было бы сделать второе развертывание для EB рядом с производственной средой, сделав еще шаг: объединив автоматически масштабируемую группу канареечного деплоя с LB развертывания в производственную среду. А раз Terraform использует ASG beantalk как вывод, это потребует 4 лишние строки кода в Terraform. Когда я поинтересовался, нет ли сопоставимого решения в CloudFormation, мне указали на целый репозиторий в git с конвейером развертывания и прочим: и все это — ради того, что могли бы сделать несчастные 4 строчки кода Terraform.


Он лучше обнаруживает дрейф


Убедитесь, что реальность соответствует ожиданиям.

Обнаружение дрейфа — очень мощная функция operations as code, потому что помогает убедиться, что реальность соответствует ожиданиям. Она доступна и с CloudFormation и с Terraform. Но по мере роста рабочего стека поиск дрейфа в CloudFormation выдавал все больше ложных обнаружений.

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


CDK и будущее CloudFormation

CloudFormation трудно управлять в крупных, межинфраструктурных масштабах. Многие из этих трудностей признаны, и инструменту нужны такие вещи как aws-cdk, структура для определения облачной инфраструктуры в коде и проведения ее через AWS CloudFormation. Будет любопытно взглянуть, что ждет aws-cdk в будущем, но ему трудно будет состязаться с другими преимуществами Terraform; чтобы подтянуть CloudFormation, потребуются глобальные изменения.


Чтобы Terraform не разочаровал


Это же «инфраструктура как КОД», а не «как текст».

Первое впечатление от Terraform у меня сложилось довольно дурное. Думаю, я просто не понял подхода. Почти все инженеры по первой невольно воспринимают его как текстовый формат, который надо преобразовать в желаемую инфраструктуру. НЕ НАДО ТАК.


Прописные истины хорошей разработки ПО относятся и к Terraform

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


Как уж код и не задокументировать?

Мне попадались огромные стеки Terraform совершенно без документации. Как можно писать код страницами — совершенно без документации? Добавляйте документацию, в которой объясняется ваш код Terraform (ударение здесь на слово «код»), почему этот раздел так важен, и что вы делаете.


Как можно разворачивать сервисы, которые некогда были одной большой функцией main ()?

Мне встречались очень сложные стеки Terraform, представленные в виде единого модуля. Почему мы так не разворачиваем ПО? Зачем дробим крупные функции на более мелкие? Те же ответы справедливы и для Terraform. Если модуль у вас слишком велик — надо его разбить на модули поменьше.


Разве ваша компания не пользуется библиотеками?

Я видел, как инженеры, раскручивая новый проект при помощи Terraform, тупо копи-пейстили громадные куски из других проектов в свои собственные, а потом ковыряли их, пока не начинало работать. Вот вы у себя в компании стали бы работать так с «боевым» кодом? Мы же не просто так пользуемся библиотеками. Да, не все должно быть библиотекой, но куда мы без общих библиотек в принципе?!


Разве вы не пользуетесь PEP8 или gofmt?

В большинстве языков есть стандартная принятая схема форматирования. В Python это PEP8. В Go — gofmt. У Terraform есть свой: terraform fmt. Пользуйтесь на здоровье!


Вы станете пользоваться React, не зная JavaScript?

Модули Terraform могут упростить какую-то часть создаваемой вами сложной инфраструктуры, но это еще не значит, что можно можно в ней вообще не шарить. Хотите правильно использовать Terraform без понимания ресурсов? Вы обречены: время будет идти, а вы так и не освоите Terraform.


Вы кодите синглтонами, или внедряя зависимости?

Внедрение зависимостей — признанная лучшая практика для разработки ПО, которую предпочитают синглтонам. Как это пригодится в Terraform? Мне встречались модули Terraform, зависящие от удаленного состояния. Вместо того, чтобы писать модули, извлекающие из удаленного состояния, напишите модуль, который принимает параметры. А потом передайте эти параметры в модуль.


Ваши библиотеки делают десять вещей хорошо или одну — отлично?

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


Как вы производите изменения в библиотеках без обратной совместимости?

Общему модулю Terraform, как и обычной библиотеке, нужно как-то сообщать пользователям об изменениях без обратной совместимости. Когда происходят такие изменения в библиотеках, это раздражает, и точно так же раздражает, когда изменения без обратной совместимости производятся в модулях Terraform. Рекомендуется применять git tags и semver при использовании модулей Terraform.


Производственный сервис запущен у вас на ноутбуке или в датацентре?

У Hashicorp есть инструменты вроде terraform cloud для запуска вашего terraform. Эти централизованные сервисы облегчают управление, аудит и одобрение изменений terraform.


Разве вы не пишете тесты?

Инженеры признают, что код нужно тестировать, но сами при этом часто забивают на проверки, работая с Terraform. Для инфраструктуры это чревато коварными моментами. Я советую «тестировать» или «создавать примеры» стеков с использованием модулей, которые можно корректно задеплоить для проверки во время CI/CD.


Terraform и микросервисы


Жизнь и смерть микросервисных компаний зависит от скорости, обновления и разрушения новых микросервисных рабочих стеков.

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

© Habrahabr.ru