Введение
Язык конфигурации HashiCorp (HCL), используемый в Terraform, обеспечивает множество полезных структур и возможностей, присутствующих в других програмming языках. Использование циклов в инфраструктурном коде может значительно уменьшить дублирование кода и улучшить читабельность, что позволяет легче осуществить будущее重构 и обеспечивает большую гибкость. HCL также обеспечивает несколько общих данных структур, таких как списки и карты (также называемые массивами и словарями соответственно в других языках), а также условные операторы для разветвления пути выполнения.
Уникально для Terraform есть возможность вручную указать зависимости ресурсов.尽管 когда вы запускаете ваш код он уже содержит выявленные связи ( которые правильны в большинстве ситуаций), иногда вам может потребоваться навязать зависимость, которую Terraform не смог обнаружить.
В этой статье мы рассмотрим данные структуры, предоставляемые HCL, его функции цикла для ресурсов (ключ count
, for_each
и for
), условные операторы для обработки известных и неизвестных значений и зависимости между ресурсами.
Предварительные требования
- Примерно так выглядят данные в русском языке:
ДигиталОcean персональный доступной токен, который можно создать через панель управления DigitalOcean. Вы можете получить инструкции в документах продуктов DigitalOcean, Как создать персональную доступную токен.
- Терраформ установлен на вашем локальном компьютере и проект развернут с помощью проваider DigitalOcean. Полностью выполните Шаг 1 и Шаг 2 из Инструкций по использованию Терраформа с DigitalOcean, и не забудьте назвать папку проекта
terraform-flexibility
, а неloadbalance
. При Шаге 2 вы не должен включать переменнуюpvt_key
и ресурс SSH-ключа при конфигурировании проваidera.
Примечание: Этот пример был тестирован при Terraform 1.0.2
.
Туры DataTypes в НСЛ
Во-первых, мы рассмотрим доступные типы данных в НСЛ и их использования.
Наш конфигурационный язык Hashicorp поддерживает простые и сложные типы данных. Простые типы данных составляют базовые типы, которые не могут быть получены из других типов. Соответственно, сложные типы группируют значения различных типов в одном. Типы сложности, например, это структурные и коллекционные типы. Структурные типы позволяют групировать значения различных типов в одну группу. Примеры таких типов присутствуют в том числе и ресурсные определения, которые вы используете для описания как будут выглядить ваши инfrastructure. В отличие от структурных типов, коллекционные типы также группируют значения, но все они имеют те же типы. Доступными в HCL тремя типами соответствия являются листы, мапы и сеты.
Мапы
Листы
Листы подобны массивам во многих других программных языках. Они содержат известное число элементов одного типа, которые можно получить используя адресацию массива ([]
), начавшись с нулевого индекса. Вот пример декларации переменной, которая содержит имена Droplet, которые вы развертываете в последующих шагах:
Для type
, вы указали, что это лист, чьи элементы имеют тип string, а также его default
значение. В HCL значения, enumerate в круглых括号, означают лист.
Карты
Маркировка – это собрание пар ключ-значение, где каждый значение доступен по своему ключу типа string
. Exist two ways to specify maps within curly braces: by using colons (:
) or equal signs (=
) for specifying values. In both cases, the value must be enclosed with quotes. When using colons, the key must also be enclosed.
The following map definition containing Droplet names for different environments is written using the equal sign:
If the key starts with a number, you must use the colon syntax:
Сеты
Сеты не поддерживают порядок элементов, что означает, что прохождение сеты не гарантирует получение того же порядка каждый раз и что их элементы не могут быть обработанными в целях получения. Они содержат уникальные элементы, которые повторяются точно один раз, и задачи, которые представляют одно и только одно значение.
Декларирование сета похоже на декларирование листа, единственным различием является тип переменной:
Теперь, после изучения типов данных, которые предоставлены HCL и реVIEW синtaxи списков, мап и сетов, которые будут использоваться во время этого обучения, вы перейдете к попытке использовать различные способы развертывания многократных экземпляров одного и того же ресурса в Terraform.
Изменение числа ресурсов при помощью ключа count
В этой секции вы создаваем множество экземпляров одного и того же ресурса используя ключ count
. Ключ count
доступен для всех ресурсов и указывает количество образов, которые следует создать.
Вы будете видеть как это работает, написав ресурс Droplet, который будет храниться в файле droplets.tf
в директории проекта, которую вы создали как часть предреquisitos. Создайте и открыйте его для редактирования командой:
Создайте и откройте его для редактирования командой:
Этот код определяет ресурс Droplet, который будет работать под управлением Ubuntu 20.04 с 1ГБ RAM и одним ядерным процессором.
Замечайте, что значение ключа count
установленно на 3
, что значит, что Terraform будет пытаться создать три экземпляра одного и того же ресурса. Когда вы закончите, сохраните и закрыть файл.
Вы можете рассмотреть проект, чтобы увидеть, какие действия Terraform будет выполнять, выполнив:
Ответ будет похож на это:
Проект был разработан с использованием Terraform, которой требуется создать три экземпляра объекта test_droplet
, все с одним именем web
. При возможности это не желательно, поэтому измените определение Droplet, чтобы имена каждого экземпляра были уникальными. Открый файл droplets.tf
для редактирования:
Измените выделенную строку:
Сохраните и закрыть файл.
Теперь функция count
предоставляет свойство index
, которое содержит индекс текущей итерации, начавшийся от 0. Текущий индекс подставляется в имеe Droplet при помощи интерполяции строки, которая позволяет вам динамически строить строку, используя переменные. Вы можете проверить проект снова, чтобы видеть изменения:
Расшифровка будет похожа на это:
Этим временем, три экземпляра test_droplet
получит свой индекс в их именах, что поможет вам более легко отслеживать их.
Вы также знаете как получать и использовать индекс экземпляра из списка во время раз provisionsing. Следующим вам научиться получать имя Droplet из списка.
Извлечение имейлов различных случаев из списка
В случаях, когда необходимо иметь имена для многих экземпляров одного и того же ресурса, вы можете получить их динамически из переменной, которую вы definиваете. В течении оставших частей этой урока вы узнаете как автоматизировать развертывание приложений Droplet из списка имейлов, предоставляя гибкость и легкость использования.
Вы первым делом должны definir список, содержащий имейлы Droplet. Создайте файл под названием variables.tf
и откройте его для редактирования:
Добавите следующие строки:
Сохраните и закрыть файл. Этот код definивает переменную droplet_names
, содержащую значения first
, second
, third
, и fourth
.
Откройте droplets.tf
для редактирования:
Измените подсвеченные строки:
Чтобы улучшить гибкость, вместо ручно definивания константы числа элементов, вы передаёте длину переменной droplet_names
в параметр count
, который всегда возвращает количество элементов в списке. Для имейла вы берут значение элемента списка, позиционно определенное значение аппаратной индексной функции. Сохраните и закрыть файл, когда вы закончите.
Попробуйте план проекта еще раз. Вы получите вывод, похожий на это:
В результате этих изменений будут созданы четыре Дроплета, которые будут называться по порядку элементами списка droplet_names
.
Вы узнали о count
, его особенности и синтаксис, и использовали его вместе с списком, чтобы модифицировать экземпляры ресурсов. Теперь вы увидите его недостатки и как их преодолеть.
Обнаружение недостатков count
Теперь, когда вы знаете, как используется count
, давайте рассмотрим его недостатки при изменении списка, с которым он используется.
Попробуйте развернуть Дроплеты в облаке:
Введите yes
, когда будет спрошено. Конец вывода будет схож следующим образом:
OutputApply complete! Resources: 4 added, 0 changed, 0 destroyed.
Теперь создадим еще один экземпляр Дроплета, увеличив список droplet_names
. Откройте variables.tf
для редактирования:
Добавьте новый элемент в начале списка:
По завершении работы сохраните и закройте файл.
План проекта:
Вы получите выход, как это:
Исход показывает, что Terraформ переименует первые четыре Приложений и создаст пятое, названное четвертом
, поскольку он рассматривает приложения как ориентированную последовательность и идентифицирует элементы (Приложения) по их индексу в списке. Это как Terraформ первоначально рассматривает первые четыре Приложений:
Index Number | 0 | 1 | 2 | 3 |
---|---|---|---|---|
Droplet Name | first | second | third | fourth |
Когда новый Приложение один
добавляется в начало, его внутренняя представление в таблицах выглядит так:
Index Number | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Droplet Name | zero | first | second | third | fourth |
Теперь первые четыре Приложения перемещены на одну позицию вправо. Терраформ затем сравнивает две стороны, которые представлены в таблицах: на позиции 0
, Приложение было названо first, и поскольку его различают во второй таблице, планируется действие обновления. Это продолжается до позиции 4
, которой не имеет аналога в первой таблице, а вместо этого планируется действие создания Приложения.
При добавлении нового элемента в список любой позиции, кроме последней, будут изменены ресурсы без необходимости. Такие же действия обновления будут произведены, если бы был удален элемент из списка droplet_names
.
Интересно, что использование count
для развертывания динамического числа одних и тех же ресурсов при работе с переменными является основным недостатком. Для случаев, когда значения некоторых атрибутов получаются из переменных, лучше всего использовать цикл for_each
, который вы узнаете позже в этой статье.
Использование текущего ресурса (self
)
Другим недостатком count
является то, что во многих случаях невозможно обращаться к любому случайно выбранному элементу ресурса его индекс.
Основной пример – правила расписания времени уничтожения, которые выполняются при планировании уничтожения ресурса. Причина в том, что запрошенный экземпляр может не существовать (уже уничтожен) или создает обратную зависимость. В таких случаях вы можете обращаться только к текущему ресурсу через ключевую фразу self
.
Для демонстрации его использования, вы теперь добавите локального обслуживателя для времени уничтожения в определение test_droplet
, который показает сообщение при запуске. Откройте droplets.tf
для редактирования:
Добавьте следующие выделенные строки:
Сохраните и закройте файл.
Обслуживатель local-exec
выполняет команду на локальном компьютере, на котором выполняется Terraform. Благодаря установке параметра when
в значение destroy
, она выполняется только когда ресурс готовится к уничтожению. Команда, которая выполняется, выводит строку в stdout
, которая заменяет имя текущего ресурса используя self.name
.
Поскольку в следующей секции вы будете создавать Droplet по-другому, уничтожьте текущие установленные выполнив следующую команду:
Введите yes
, когда вам будет спрошено. Вы будете получать выполнение обслуживателя local-exec
четыре раза:
В этом шаге вы узнали недостатки опции count
. Теперь вы узнаете о конструкции цикла for_each
, которая преодолевает их и работает с более широким набором типов переменных.
Использование цикла for_each
В этой секции вы рассмотрите цикл for_each
, его синтаксис и то, как он помогает обеспечить гибкость при определении ресурсов с множеством экземпляров.
for_each
– это параметр, доступный для каждого ресурса, но в отличие от count
, который требует количество экземпляров для создания, for_each
принимает карту или набор. Каждый элемент предоставленного собрания идет по кругу один раз, и для него создается экземпляр. Параметр for_each
делает ключ и значение доступными под ключем each
в качестве атрибутов (ключ и значение пары как each.key
и each.value
, соответственно). Когда для него передается набор, ключ и значение будут одинаковыми.
Благодаря тому, что он предоставляет текущий элемент в объекте each
, вам не придется вручную доступать к нужному элементу, как было при работе с списками. В случае с наборами это вообще невозможно, так как у него внутреннего порядка нет. Списки также можно передать, но их сначала нужно преобразовать в набор с помощью функции toset
.
Основное преимущество использования for_each
заключается в том, что можно перечислить все три типа данных собрания и чтолько самые затронутые элементы будут изменены, созданы или удалены. Если вы измените порядок элементов в входных данных, никакие действия не будут планироваться, и если вы добавите, удалите или измените элемент в входных данных, соответствующие действия будут планироваться только для этого элемента.
Перенесим ресурс Droplet из count
в for_each
и посмотрим, как это работает на практике. Откройте droplets.tf
для редактирования, запустив:
Измените выделенные строки:
Вы можете удалить настраиватель local-exec
. После этого сохраните и закройте файл.
Первая строка заменяет count
и вызывает for_each
, передавая в форме сетa droplet_names
используя функцию toset
. Для имени Droplet вы указываете each.value
, которая содержит значение текущего элемента из сеты имений Droplet.
План проекта будет рассмотрен так:
Вывод будет описать шаги, которые Terraform принимает:
Контрастно к использованию count
, Terraform теперь рассматривает каждый экземплёнр индивидуально, а не как элементы орdered листа. Каждый экземплёнр связается с элементом полученного сетa, как показано строкой элементов в круглых括号, которые будут созданы.
Используйте команду для приложения плана к облаку:
Введите yes
когда вызовется вопрос. Когда он завершится, вы удалите одну элемент из сетa droplet_names
чтобы показать, что другие экземплёнры не будутaffected. Откройте файл variables.tf
для редактирования:
Измените список, чтобы он выглядел так:
Сохраните и закройте файл.
Планируйте проект снова, и вы получите следующий результат:
На этот раз Terraform будет удалять только удаленный экземпляр (zero
) и не трогать никакие другие экземпляры, что является correct behavior.
В этом шаге вы узнали о for_each
, как его использовать и преимущества перед count
. далее вы узнаете о цикле for
, его синтаксис и использование, и когда он может использоваться для автоматизации определенных задач.
Использование цикла for
Цикл for
работает с коллекциями и создает новую коллекцию, применяя трансформацию к каждому элементу входного значения. точный тип выхода будет зависеть от того, окружен ли цикл скобками ([]
) или сетками ({}
), которые дают список или карту соответственно. поэтому он подходит для запроса ресурсов и создания структурированных выходов для последующей обработки.
Общий синтаксис цикла for
выглядит так:
Схоже с другими языками программирования, сначала вы должны назвать переменную для перебора (element
) и указать collection
, которую надо перечислить. Тело цикла является этапом трансформации, а необязательное условие if
может использоваться для фильтрации входной коллекции.
Теперь вы будете работать с несколькими примерами с выходами. Вы сохраните их в файле с именем outputs.tf
. Создайте его для редактирования, выполнив следующий команду:
Добавьте следующие строки для вывода пар имён установленных Droplets и их IP-адресов:
Этот код определяет выход с именем ip_addresses
и указывает цикл for
, который итерает по экземплярам ресурса test_droplet
, которые вы настраиваете в предыдущих шагах. Т.к. цикл окружен скобками, его выход будет картой. Этап трансформации для карт похож на lambda функции в других языках программирования, и в этом месте он создает пару ключ-значение, объединяя имя экземпляра в качестве ключа с его частным IP в качестве значения.
Сохраните и закройте файл, а затем обновите Terraform state, чтобы учесть новый выход, выполнив:
COMMAND_NOT_FOUND.
Потом проверьте содержимое выходов:
Технология Terraform показала содержание выхода, который составлен из мапы, полученной в результате исполнения цикла. (Содержание записей может быть разным для вас.) Цикл работает без проблем для любого числа элементов — значит, что вы можете добавить новый элемент в список droplet_names
, и новый Droplet будет также создан без дополнительного ручного ввода, и это также появится в этой выходной конфигурации автоматически.
Вот как вы можете получить лист, округлив блоки for
. Например, вы можете получить адресы IP Droplet, которыеUseful for external software that may be parsing the data. The code would look like this:
Here, the transformational step selects the IP address attribute. It would give the following output:
As was noted before, you can also filter the input collection using the if
clause. Here is how you would write the loop to filter by the fra1
region:
In HCL, the ==
operator checks the equality of the values of the two sides—here it checks if instance.region
is equal to fra1
. If it is, the check passes and the instance
is transformed and added to the output, otherwise it is skipped. The output of this code would be the same as the prior example, because all Droplet instances are in the fra1
region, according to the test_droplet
resource definition. The if
conditional is also useful when you want to filter the input collection for other values in your project, like the Droplet size or distribution.
Прежде чем выполнить приведенную ниже команду, удалите все текущие развертывания проектов, используя следующий команд:
Вы введите yes
, когда будет предложен вопрос о завершении процесса.
Вы узнали о форме и принципах работы цикла for
, примеры его использования в выходах. Теперь вы узнаете о кондиционалах и как их можно использовать вместе с ключем count
.
Директивы и Кондиционалы
В одном из предыдущих разделов вы видели ключ count
и как он работает. Вы также получили информацию о том, как использовать тривиальные кондициональные операторы, которые могут быть использованы в вашем коде Terraform помимо count
.
Синtax тривиального оператора составляется так:
condition
– это выражение, которое вычисляется до значения bool (true или false). Если условие true, то выражение evalуате value_if_true
. НаовTHERwise, результатом будет value_if_false
.
Основное применение тривиальных операторов – позволить или отключить создание одного и только одного ресурса в соответствии с содержимом переменной. Это может быть достигнуто путем передачи результата сравнения (either 1
or 0
) в ключ count
на желаемый ресурс.
При использовании оператора присваивания для получения одного элемента из списка или множества, вы можете использовать функцию one
. Если переданный коллекция пустая, она возвращает null
. В противном случае, она возвращает единственный элемент в коллекции, или выбрасывает ошибку, если имеется более одного.
Добавим переменную create_droplet
, которая будет управлять созданием Droplet. Первым делом откройте файл variables.tf
для редактирования:
Добавите выделенные строки:
Этот код определяет переменную create_droplet
типа bool
. Сохраните и закрыть файл.
Тогда, чтобы изменитьDeclaration Droplet, откройте droplets.tf
для редактирования, выполнив:
Измените ваш файл так, как показано ниже:
В count
вы используем оператор присваивания триалистического типа, чтобы вернуть либо 1
, если значение переменной create_droplet
равно true
, либо 0
, если false
, который будет привести к тому, что не будут развертываться ни одних Droplet. Сохраните и закрыть файл, когда вы закончите.
План выполнения проекта с установкой значения переменной на false
выполнить командой:
Вы получите следующий вывод:
Поскольку create_droplet
был передан значение false
, значение count
становится 0
, и ни одного Droplet не будет создано, поэтому не будет выдаваться ни одной IP-адреса для вывода.
Вы уже выучили, как использовать трёхчленный оператор условного выражения вместе с ключом count
, чтобы обеспечить более высокий уровень гибкости в выборе, необходимо ли развернуть желаемые ресурсы. далее вы узнаете о явном установлении зависимостей ресурсов для ваших ресурсов.
Явное установление зависимостей ресурсов
При создании плана выполнения проекта Terraform обнаруживает цепочки зависимости между ресурсами и явно их упорядочивает, чтобы они были построены в соответствующем порядке. В большинстве случаев Terraform способен обнаружить связи, сканируя все выражения в ресурсах и строя граф.
Однако, когда один ресурс, для его развертывания, требует уже установленных на cloud provider управляющих устройствами доступа, Terraform не имеет явных признаков, связывающих их. Кроме того, Terraform не будет знать, что они связаны поведенчески. В таких случаях зависимость должна быть явно указана с использованием аргумента depends_on
.
Ключ depends_on
доступен для каждого ресурса и используется для определения скрытых связей между конкретными ресурсами. Скрытые связи формируются, когда ресурс зависит от поведения другого ресурса, не используя его данные в своем определении, что заставляет Terraform соединить их один с другим.
Вот пример, как depends_on
определяется в коде:
Она принимает список ссылок на другие ресурсы и не принимает произвольные выражения.
depends_on
следует использоваться с осторожностью и только в тех случаях, когда все другие варианты исчерпаны. Его использование указывает, что вы пытаетесь объявить те, что вы делаете, выходящими за рамки автоматической системы обнаружения зависимостей Terraform; это может указывать, что ресурс зависит от более чем необходимого количества ресурсов.
Теперь вы узнали о явном настройке дополнительных зависимостей для ресурса с помощью ключа depends_on
и когда его следует использовать.
Заключение
В этой статье мы просмотрели функции HCL, которые улучшают гибкость и масштабность вашего кода, такие как count
для указания количества экземпляров ресурсов, которые должны быть развернуты, и for_each
как усовершенствованный способ цикла по собраниям данных и настраивания экземпляров. Если они используются правильно, это значительно уменьшает дублирование кода и операционные расходы на управление развернутой инфраструктурой.
Вы также узнали о условных операторах и трёхчленных операторах и то, как их можно использовать, чтобы контролировать, будет ли развернут ресурс.尽管 Terraform的自动化依赖分析系统相当强大,但仍有一些情况下您可能需要手动使用 depends_on
键指定资源依赖。
Этот пример является частью серии Как управлять инфраструктурой с Terraform . Серия рассматривает ряд тем, от первого использования Terraform до управления сложными проектами.