Terraform против CloudFormation: подробное руководство

Опубликовано: 2022-03-11

Если вы, как и я, рыскали в Интернете, чтобы выбрать между CloudFormation и Terraform в качестве следующего инструмента инфраструктуры как кода (IaC), но не нашли окончательного ответа, я долгое время разделял вашу боль. Теперь у меня есть значительный опыт работы с обоими инструментами, и я могу принять обоснованное решение о том, какой из них использовать.

TL;DR

Для вашего проекта IaC на AWS выберите CloudFormation, потому что:

  1. CloudFormation проводит различие между кодом (т. е. шаблонами) и экземплярами кода (т. е. стеками). В Terraform такого различия нет. Подробнее об этом в следующем разделе.
  2. Terraform не очень хорошо справляется с базовым управлением зависимостями. Подробнее об этом в следующем разделе.

Различие между кодом и экземплярами

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

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

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

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

Terraform на самом деле не имеет концепции стеков , такой как CloudFormation, что ясно показывает, что Terraform был построен с нуля, чтобы иметь прямое соответствие между кодом и ресурсами, которыми он управляет. Позже это было частично исправлено концепцией сред (которые с тех пор были переименованы в «рабочие области»), но способ их использования делает невероятно простым развертывание в нежелательной среде. Это связано с тем, что вам нужно запустить terraform workspace select перед развертыванием, и если вы забудете об этом шаге, произойдет развертывание в ранее выбранной рабочей области, которая может быть или не быть той, которую вы хотите.

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

Управление состоянием и разрешения

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

CloudFormation управляет состоянием стека за вас и не дает вам никаких вариантов. Но по моему опыту состояния стека CloudFormation были надежными. Кроме того, CloudFormation позволяет менее привилегированным пользователям управлять стеками, не имея всех необходимых разрешений, требуемых самим стеком. Это связано с тем, что CloudFormation может получить разрешения от роли службы, прикрепленной к стеку, а не разрешения от пользователя, выполняющего операцию стека.

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

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

Поэтому вам нужно надежное и совместно используемое состояние, которое в AWS обычно достигается за счет использования корзины S3 для хранения файла состояния, сопровождаемой таблицей DynamoDB для обработки параллелизма.

Это означает, что вам нужно вручную создать корзину S3 и таблицу DynamoDB для каждого стека, который вы хотите создать, а также вручную управлять разрешениями для этих двух объектов, чтобы запретить менее привилегированным пользователям доступ к данным, к которым у них не должно быть доступа. Если у вас всего пара стеков, это не будет большой проблемой, но если вам нужно управлять 20 стеками, это становится очень громоздким.

Кстати, при использовании рабочих областей Terraform невозможно иметь одну таблицу DynamoDB на каждую рабочую область. Это означает, что если вы хотите, чтобы пользователь IAM с минимальными разрешениями выполнял развертывание, этот пользователь сможет возиться с блокировками всех рабочих областей, поскольку разрешения DynamoDB не детализированы до уровня элемента.

Управление зависимостями

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

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

Учитывая, что правильное управление зависимостями абсолютно необходимо для инструмента IaC, такие проблемы в Terraform ставят под сомнение его пригодность, как только задействованы критически важные для бизнеса операции, такие как развертывание в производственной среде. CloudFormation дает гораздо более профессиональный вид, и AWS всегда очень внимательно следит за тем, чтобы предлагать своим клиентам инструменты производственного уровня. За все годы использования CloudFormation я ни разу не сталкивался с проблемой управления зависимостями.

CloudFormation позволяет стеку экспортировать некоторые из своих выходных переменных, которые затем могут повторно использоваться другими стеками. Честно говоря, эта функциональность ограничена, так как вы не сможете создать более одного стека для каждого региона. Это связано с тем, что вы не можете экспортировать две переменные с одинаковыми именами, а у экспортируемых переменных нет пространств имен.

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

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

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

 Error: Error deleting Target Group: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:723207552760:targetgroup/strategy-api-default-us-east-1/14a4277881e84797' is currently in use by a listener or a rule status code: 400, request id: 833d8475-f702-4e01-aa3a-d6fa0a141905

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

Операции

Хотя Terraform — это инструмент командной строки, совершенно очевидно, что он ожидает, что его будет запускать человек, поскольку он очень интерактивен. Его можно запустить в пакетном режиме (т. е. из скрипта), но для этого потребуются дополнительные аргументы командной строки. Тот факт, что Terraform был разработан для запуска людьми по умолчанию, весьма озадачивает, учитывая, что целью инструмента IaC является автоматизация.

Terraform сложно отлаживать. Сообщения об ошибках часто очень просты и не позволяют вам понять, что происходит не так, и в этом случае вам придется запускать Terraform с TF_LOG=debug , что приводит к огромному объему вывода для просмотра. Это усложняет то, что Terraform иногда делает неудачные вызовы API к AWS, но сбой не является проблемой для Terraform. Напротив, CloudFormation предоставляет достаточно четкие сообщения об ошибках с достаточным количеством деталей, чтобы вы могли понять, в чем проблема.

Пример сообщения об ошибке Terraform:

 Error: error reading S3 bucket Public Access Block: NoSuchBucket: The specified bucket does not exist status code: 404, request id: 19AAE641F0B4AC7F, host id: rZkgloKqxP2/a2F6BYrrkcJthba/FQM/DaZnj8EQq/5FactUctdREq8L3Xb6DgJmyKcpImipv4s=

Приведенное выше сообщение об ошибке показывает четкое сообщение об ошибке, которое на самом деле не отражает основную проблему (в данном случае это была проблема с разрешениями).

Это сообщение об ошибке также показывает, как иногда Terraform может загнать себя в угол. Например, если вы создаете ведро S3 и ресурс aws_s3_bucket_public_access_block в этом ведре, и если по какой-то причине вы вносите некоторые изменения в код Terraform, которые уничтожают это ведро — например, в описанной выше ошибке «изменение подразумевает удаление и создание» — Terraform застрянет, пытаясь загрузить aws_s3_bucket_public_access_block но постоянно терпит неудачу с вышеуказанной ошибкой. Правильным поведением Terraform было бы заменить или удалить aws_s3_bucket_public_access_block по мере необходимости.

Наконец, вы не можете использовать вспомогательные сценарии CloudFormation с Terraform. Это может раздражать, особенно если вы надеетесь использовать cfn-signal, который сообщает CloudFormation, что инстанс EC2 завершил свою инициализацию и готов обслуживать запросы.

Синтаксис, сообщество и откат

С точки зрения синтаксиса у Terraform есть хорошее преимущество по сравнению с CloudFormation — он поддерживает циклы. Но по моему собственному опыту, эта функция может оказаться немного опасной. Как правило, цикл используется для создания ряда идентичных ресурсов; однако, если вы хотите обновить стек с другим количеством, может возникнуть вероятность того, что вам может понадобиться связать старый и новый ресурсы (например, используя zipmap() для объединения значений из двух массивов, которые теперь оказались разных размеров, потому что один массив имеет размер старого размера цикла, а другой имеет размер нового размера цикла). Это правда, что такая проблема может возникнуть и без циклов, но без циклов проблема была бы гораздо более очевидной для человека, пишущего сценарий. Использование циклов в таком случае запутывает проблему.

Что лучше синтаксис Terraform или CloudFormation, в основном зависит от предпочтений. Изначально CloudFormation поддерживал только JSON, но шаблоны JSON очень трудно читать. К счастью, CloudFormation также поддерживает YAML, который намного легче читать и позволяет комментировать. Однако синтаксис CloudFormation довольно многословен.

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

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

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

И последний момент, который на самом деле может быть спорным, заключается в том, что CloudFormation пытается откатить неудачные развертывания. Это довольно интересная функция, но, к сожалению, может быть очень долгой (например, CloudFormation может потребоваться до трех часов, чтобы решить, что развертывание в Elastic Container Service не удалось). Напротив, в случае сбоя Terraform просто останавливается, где бы он ни был. Можно спорить о том, хороша функция отката или нет, но я пришел к выводу, что стек поддерживается в рабочем состоянии в максимально возможной степени, когда более длительное ожидание является приемлемым компромиссом.

В защиту Terraform против CloudFormation

У Terraform есть преимущества перед CloudFormation. Самым важным, на мой взгляд, является то, что при применении обновления Terraform показывает вам все изменения, которые вы собираетесь внести, включая детализацию всех модулей, которые он использует. В отличие от этого, CloudFormation при использовании вложенных стеков только показывает, что вложенный стек нуждается в обновлении, но не дает возможности углубиться в детали. Это может быть неприятно, так как этот тип информации очень важно знать, прежде чем нажимать кнопку «Перейти».

И CloudFormation, и Terraform поддерживают расширения. В CloudFormation можно управлять так называемыми «настраиваемыми ресурсами», используя созданную вами функцию AWS Lambda в качестве серверной части. Для Terraform гораздо проще писать расширения, которые являются частью кода. Так что в этом случае у Terraform есть преимущество.

Terraform может работать со многими облачными поставщиками. Это дает Terraform возможность унифицировать данное развертывание между несколькими облачными платформами. Например, предположим, что у вас есть одна рабочая нагрузка, распределенная между AWS и Google Cloud Platform (GCP). Обычно часть рабочей нагрузки AWS развертывается с помощью CloudFormation, а часть GCP — с помощью GCP Cloud Deployment Manager. Вместо этого с Terraform вы можете использовать один сценарий для развертывания и управления обоими стеками на соответствующих облачных платформах. Таким образом, вам нужно развернуть только один стек вместо двух.

Не аргументы в пользу Terraform против CloudFormation

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

Некоторые утверждают, что с помощью Terraform можно избежать привязки к поставщику. Этот аргумент не имеет силы в том смысле, что при использовании Terraform вас блокирует HashiCorp (создатель Terraform), точно так же, как при использовании CloudFormation вас блокирует AWS, и так далее для других облачных сервисов. платформы.

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

На более личном уровне я полностью понимаю преимущества использования библиотек в случае разработки программного обеспечения, поскольку эти библиотеки могут легко работать с десятками тысяч строк кода. Однако в случае IaC размер кода обычно намного меньше, а длина таких модулей обычно составляет несколько десятков строк. Использование копирования/вставки на самом деле не такая уж плохая идея в том смысле, что она позволяет избежать проблем с поддержанием совместимости и делегированием вашей безопасности неизвестным людям.

Использование копирования/вставки не одобряется многими разработчиками и инженерами DevOps, и для этого есть веские причины. Однако моя точка зрения заключается в том, что использование копирования/вставки для фрагментов кода позволяет легко адаптировать его под свои нужды, и нет необходимости делать из него библиотеку и тратить много времени на то, чтобы сделать его универсальным. Боль от поддержки этих фрагментов кода обычно очень невелика, если только ваш код не дублируется, скажем, в дюжине или более шаблонах. В таком случае присвоение кода и его использование в качестве вложенных стеков имеет смысл, и преимущества от того, чтобы не повторяться, вероятно, больше, чем раздражение от невозможности увидеть, что будет обновлено внутри вложенного стека, когда вы выполняете обновление. операция.

CloudFormation против Terraform Заключение

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

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

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