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

Введение

Язык конфигурации 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, которые вы развертываете в последующих шагах:

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third"]
}

Для 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:

variable "droplet_env_names" {
  type = map(string)

  default = {
    development = "dev-droplet"
    staging = "staging-droplet"
    production = "prod-droplet"
  }
}

If the key starts with a number, you must use the colon syntax:

variable "droplet_env_names" {
  type = map(string)

  default = {
    "1-development": "dev-droplet"
    "2-staging": "staging-droplet"
    "3-production": "prod-droplet"
  }
}

Сеты

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

Декларирование сета похоже на декларирование листа, единственным различием является тип переменной:

variable "droplet_names" {
  type    = set(string)
  default = ["first", "second", "third", "fourth"]
}

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

Изменение числа ресурсов при помощью ключа count

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

Вы будете видеть как это работает, написав ресурс Droplet, который будет храниться в файле droplets.tf в директории проекта, которую вы создали как часть предреquisitos. Создайте и открыйте его для редактирования командой:

  1. nano droplets.tf

Создайте и откройте его для редактирования командой:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Этот код определяет ресурс Droplet, который будет работать под управлением Ubuntu 20.04 с 1ГБ RAM и одним ядерным процессором.

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

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

  1. terraform plan -var "do_token=${DO_PAT}"

Ответ будет похож на это:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: digitalocean_droplet.test_droplet[0] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } digitalocean_droplet.test_droplet[1] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } digitalocean_droplet.test_droplet[2] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } Plan: 3 to add, 0 to change, 0 to destroy. ...

Проект был разработан с использованием Terraform, которой требуется создать три экземпляра объекта test_droplet, все с одним именем web. При возможности это не желательно, поэтому измените определение Droplet, чтобы имена каждого экземпляра были уникальными. Открый файл droplets.tf для редактирования:

  1. nano droplets.tf

Измените выделенную строку:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web.${count.index}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Сохраните и закрыть файл.

Теперь функция count предоставляет свойство index, которое содержит индекс текущей итерации, начавшийся от 0. Текущий индекс подставляется в имеe Droplet при помощи интерполяции строки, которая позволяет вам динамически строить строку, используя переменные. Вы можете проверить проект снова, чтобы видеть изменения:

  1. terraform plan -var "do_token=${DO_PAT}"

Расшифровка будет похожа на это:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.test_droplet[0] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web.0" ... } # digitalocean_droplet.test_droplet[1] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web.1" ... } # digitalocean_droplet.test_droplet[2] будет создан + resource "digitalocean_droplet" "test_droplet" { ... name = "web.2" ... } Plan: 3 to add, 0 to change, 0 to destroy. ...

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

Вы также знаете как получать и использовать индекс экземпляра из списка во время раз provisionsing. Следующим вам научиться получать имя Droplet из списка.

Извлечение имейлов различных случаев из списка

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

Вы первым делом должны definir список, содержащий имейлы Droplet. Создайте файл под названием variables.tf и откройте его для редактирования:

  1. nano variables.tf

Добавите следующие строки:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

Сохраните и закрыть файл. Этот код definивает переменную droplet_names, содержащую значения first, second, third, и fourth.

Откройте droplets.tf для редактирования:

  1. nano droplets.tf

Измените подсвеченные строки:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Чтобы улучшить гибкость, вместо ручно definивания константы числа элементов, вы передаёте длину переменной droplet_names в параметр count, который всегда возвращает количество элементов в списке. Для имейла вы берут значение элемента списка, позиционно определенное значение аппаратной индексной функции. Сохраните и закрыть файл, когда вы закончите.

Попробуйте план проекта еще раз. Вы получите вывод, похожий на это:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.test_droplet[0] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } # digitalocean_droplet.test_droplet[1] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } # digitalocean_droplet.test_droplet[2] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } # digitalocean_droplet.test_droplet[3] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... Plan: 4 to add, 0 to change, 0 to destroy. ...

В результате этих изменений будут созданы четыре Дроплета, которые будут называться по порядку элементами списка droplet_names.

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

Обнаружение недостатков count

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

Попробуйте развернуть Дроплеты в облаке:

  1. terraform apply -var "do_token=${DO_PAT}"

Введите yes, когда будет спрошено. Конец вывода будет схож следующим образом:

Output
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Теперь создадим еще один экземпляр Дроплета, увеличив список droplet_names. Откройте variables.tf для редактирования:

  1. nano variables.tf

Добавьте новый элемент в начале списка:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["zero", "first", "second", "third", "fourth"]
}

По завершении работы сохраните и закройте файл.

План проекта:

  1. terraform plan -var "do_token=${DO_PAT}"

Вы получите выход, как это:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create ~ update in-place Terraform will perform the following actions: # digitalocean_droplet.test_droplet[0] будет обновлен в месте ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "first" -> "zero" ... } # digitalocean_droplet.test_droplet[1] будет обновлен в месте ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "second" -> "first" ... } # digitalocean_droplet.test_droplet[2] будет обновлен в месте ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "third" -> "second" ... } # digitalocean_droplet.test_droplet[3] будет обновлен в месте ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "fourth" -> "third" ... } # digitalocean_droplet.test_droplet[4] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } Plan: 1 to add, 4 to change, 0 to destroy. ...

Исход показывает, что 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 для редактирования:

  1. nano droplets.tf

Добавьте следующие выделенные строки:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"

  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Droplet ${self.name} is being destroyed!'"
  }
}

Сохраните и закройте файл.

Обслуживатель local-exec выполняет команду на локальном компьютере, на котором выполняется Terraform. Благодаря установке параметра when в значение destroy, она выполняется только когда ресурс готовится к уничтожению. Команда, которая выполняется, выводит строку в stdout, которая заменяет имя текущего ресурса используя self.name.

Поскольку в следующей секции вы будете создавать Droplet по-другому, уничтожьте текущие установленные выполнив следующую команду:

  1. terraform destroy -var "do_token=${DO_PAT}"

Введите yes, когда вам будет спрошено. Вы будете получать выполнение обслуживателя local-exec четыре раза:

Output
... digitalocean_droplet.test_droplet[0] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet first is being destroyed!'"] digitalocean_droplet.test_droplet[1] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet second is being destroyed!'"] digitalocean_droplet.test_droplet[1] (local-exec): Droplet second is being destroyed! digitalocean_droplet.test_droplet[2] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet third is being destroyed!'"] digitalocean_droplet.test_droplet[2] (local-exec): Droplet third is being destroyed! digitalocean_droplet.test_droplet[3] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet fourth is being destroyed!'"] digitalocean_droplet.test_droplet[3] (local-exec): Droplet fourth is being destroyed! digitalocean_droplet.test_droplet[0] (local-exec): Droplet first is being destroyed! ...

В этом шаге вы узнали недостатки опции 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 для редактирования, запустив:

  1. nano droplets.tf

Измените выделенные строки:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  for_each = toset(var.droplet_names)
  image    = "ubuntu-20-04-x64"
  name     = each.value
  region   = "fra1"
  size     = "s-1vcpu-1gb"
}

Вы можете удалить настраиватель local-exec. После этого сохраните и закройте файл.

Первая строка заменяет count и вызывает for_each, передавая в форме сетa droplet_names используя функцию toset. Для имени Droplet вы указываете each.value, которая содержит значение текущего элемента из сеты имений Droplet.

План проекта будет рассмотрен так:

  1. terraform plan -var "do_token=${DO_PAT}"

Вывод будет описать шаги, которые Terraform принимает:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.test_droplet["first"] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } # digitalocean_droplet.test_droplet["fourth"] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } # digitalocean_droplet.test_droplet["second"] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } # digitalocean_droplet.test_droplet["third"] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } # digitalocean_droplet.test_droplet["zero"] будет создан + resource "digitalocean_droplet" "test_droplet" { ... + name = "zero" ... } Plan: 5 to add, 0 to change, 0 to destroy. ...

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

Используйте команду для приложения плана к облаку:

  1. terraform apply -var "do_token=${DO_PAT}"

Введите yes когда вызовется вопрос. Когда он завершится, вы удалите одну элемент из сетa droplet_names чтобы показать, что другие экземплёнры не будутaffected. Откройте файл variables.tf для редактирования:

  1. nano variables.tf

Измените список, чтобы он выглядел так:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

Сохраните и закройте файл.

Планируйте проект снова, и вы получите следующий результат:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: # digitalocean_droplet.test_droplet["zero"] будет удален - resource "digitalocean_droplet" "test_droplet" { ... - name = "zero" -> null ... } Plan: 0 to add, 0 to change, 1 to destroy. ...

На этот раз Terraform будет удалять только удаленный экземпляр (zero) и не трогать никакие другие экземпляры, что является correct behavior.

В этом шаге вы узнали о for_each, как его использовать и преимущества перед count. далее вы узнаете о цикле for, его синтаксис и использование, и когда он может использоваться для автоматизации определенных задач.

Использование цикла for

Цикл for работает с коллекциями и создает новую коллекцию, применяя трансформацию к каждому элементу входного значения. точный тип выхода будет зависеть от того, окружен ли цикл скобками ([]) или сетками ({}), которые дают список или карту соответственно. поэтому он подходит для запроса ресурсов и создания структурированных выходов для последующей обработки.

Общий синтаксис цикла for выглядит так:

for element in collection:
transform(element)
if condition

Схоже с другими языками программирования, сначала вы должны назвать переменную для перебора (element) и указать collection, которую надо перечислить. Тело цикла является этапом трансформации, а необязательное условие if может использоваться для фильтрации входной коллекции.

Теперь вы будете работать с несколькими примерами с выходами. Вы сохраните их в файле с именем outputs.tf. Создайте его для редактирования, выполнив следующий команду:

  1. nano outputs.tf

Добавьте следующие строки для вывода пар имён установленных Droplets и их IP-адресов:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = {
    for instance in digitalocean_droplet.test_droplet:
    instance.name => instance.ipv4_address
  }
}

Этот код определяет выход с именем ip_addresses и указывает цикл for, который итерает по экземплярам ресурса test_droplet, которые вы настраиваете в предыдущих шагах. Т.к. цикл окружен скобками, его выход будет картой. Этап трансформации для карт похож на lambda функции в других языках программирования, и в этом месте он создает пару ключ-значение, объединяя имя экземпляра в качестве ключа с его частным IP в качестве значения.

Сохраните и закройте файл, а затем обновите Terraform state, чтобы учесть новый выход, выполнив:

  1. terraform refresh -var "do_token=${DO_PAT}"

COMMAND_NOT_FOUND.

Потом проверьте содержимое выходов:

Output
ip_addresses
= { "first" = "ip_address" "fourth" = "ip_address" "second" = "ip_address" "third" = "ip_address" }

Технология Terraform показала содержание выхода, который составлен из мапы, полученной в результате исполнения цикла. (Содержание записей может быть разным для вас.) Цикл работает без проблем для любого числа элементов — значит, что вы можете добавить новый элемент в список droplet_names, и новый Droplet будет также создан без дополнительного ручного ввода, и это также появится в этой выходной конфигурации автоматически.

Вот как вы можете получить лист, округлив блоки for. Например, вы можете получить адресы IP Droplet, которыеUseful for external software that may be parsing the data. The code would look like this:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
  ]
}

Here, the transformational step selects the IP address attribute. It would give the following output:

Output
ip_addresses
= [ "ip_address", "ip_address", "ip_address", "ip_address", ]

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:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
    if instance.region == "fra1"
  ]
}

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.

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

  1. terraform destroy -var "do_token=${DO_PAT}"

Вы введите yes, когда будет предложен вопрос о завершении процесса.

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

Директивы и Кондиционалы

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

Синtax тривиального оператора составляется так:

condition ? value_if_true : value_if_false

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 для редактирования:

  1. nano variables.tf

Добавите выделенные строки:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

variable "create_droplet" {
  type = bool
  default = true
}

Этот код определяет переменную create_droplet типа bool. Сохраните и закрыть файл.

Тогда, чтобы изменитьDeclaration Droplet, откройте droplets.tf для редактирования, выполнив:

  1. nano droplets.tf

Измените ваш файл так, как показано ниже:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = var.create_droplet ? 1 : 0
  image  = "ubuntu-20-04-x64"
  name   =  "test_droplet"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

В count вы используем оператор присваивания триалистического типа, чтобы вернуть либо 1, если значение переменной create_droplet равно true, либо 0, если false, который будет привести к тому, что не будут развертываться ни одних Droplet. Сохраните и закрыть файл, когда вы закончите.

План выполнения проекта с установкой значения переменной на false выполнить командой:

  1. terraform plan -var "do_token=${DO_PAT}" -var "create_droplet=false"

Вы получите следующий вывод:

Output
Changes to Outputs: + ip_addresses = {} You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Поскольку create_droplet был передан значение false, значение count становится 0, и ни одного Droplet не будет создано, поэтому не будет выдаваться ни одной IP-адреса для вывода.

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

Явное установление зависимостей ресурсов

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

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

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

Вот пример, как depends_on определяется в коде:

resource "digitalocean_droplet" "droplet" {
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"

  depends_on = [
    # Ресурсы...
  ]
}

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

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

Теперь вы узнали о явном настройке дополнительных зависимостей для ресурса с помощью ключа depends_on и когда его следует использовать.

Заключение

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

Вы также узнали о условных операторах и трёхчленных операторах и то, как их можно использовать, чтобы контролировать, будет ли развернут ресурс.尽管 Terraform的自动化依赖分析系统相当强大,但仍有一些情况下您可能需要手动使用 depends_on 键指定资源依赖。

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

Source:
https://www.digitalocean.com/community/tutorials/how-to-improve-flexibility-using-terraform-variables-dependencies-and-conditionals