Как использовать динамический блок terraform для создания нескольких интерфейсных IP-адресов в балансировщике нагрузки az, который использует общедоступные IP-адреса для зон доступности Azure

Проблема, с которой я сталкиваюсь, касается внешнего IP-адреса балансировщика нагрузки, чтобы он мог использовать уникальный общедоступный IP-адрес для доступа к другому серверу в другой зоне доступности. Я использую счетчик для создания общедоступных IP-адресов, но я не использую счетчик в балансировщике нагрузки, потому что мне не нужен новый LB для каждого сервера. Если бы я мог каким-то образом сохранить общедоступные IP-адреса в переменной, я мог бы ссылаться на них, используя for_each внутри динамического блока, но я не могу найти способ сделать это. Вот код, который у меня есть, но он не может работать как есть. У этой проблемы может не быть решения, что действительно воняет. Кстати, я использую функцию разделения ниже, поэтому она возвращает список, который нужен свойствам. Это немного взломано, но работает.

resource "azurerm_public_ip" "pip" {
  count               = "${var.nblinuxvms}"
  name                = "${var.proj_name}-lbpip${count.index}-${var.region}-${var.app_env}"
  location            =  var.region
  resource_group_name = "${azurerm_resource_group.rg.name}"
  allocation_method   = "Static"   #Public IP Standard SKUs require allocation_method to be set to Static
  sku                 = "Standard" #Standard SKU Required for Zones
  domain_name_label   = "${var.proj_name}${count.index}${split("", "${element(["1", "2", "3"], "${count.index}")}")}"
  zones = "${var.avzones}" ? split("", "${element(["1", "2", "3"], "${count.index}")}") : null
}
resource "azurerm_lb" "lb" {
  name                = "externallb"
  location            = "${azurerm_resource_group.rg.location}"
  resource_group_name = "${azurerm_resource_group.rg.name}"
  sku                 = "standard" #standard SKU needed to support zones
 dynamic "frontend_ip_configuration" {
   for_each             = "${azurerm_public_ip.test.*.ip_address}" #this is the problem line. I need a way to store all the IPs in a variable and then iterate through them for each new frontend ip configuration
   content{
     name  = "primary${count.index}" #This name is also important as this is how I'll connect the nat rule down below
     public_ip_address_id = "${azurerm_public_ip.pip.id}"
  }
resource "azurerm_lb_nat_rule" "lbnr" {
  count                          = "${var.nblinuxvms}"
  resource_group_name            = "${azurerm_resource_group.rg.name}"
  loadbalancer_id                = "${azurerm_lb.lb.id}"
  name                           = "SSHHost${count.index}"
  protocol                       = "Tcp"
  frontend_port                  = "${2200 + count.index}"
  backend_port                   = 22
  frontend_ip_configuration_name = "primary${count.index}" #This name needs to match the LB Front End IP Configuartion
}

Имя frontend_ip_configuration_name должно совпадать с именем балансировщика нагрузки. Динамический блок с for_each кажется лучшим решением для конкретной проблемы, поскольку это не ресурс... но я не вижу способа сохранить общедоступный IP-адрес для любых переменных, на которые я могу ссылаться. Если решения нет, как люди его решают? Создавая отдельный LB для каждой зоны доступности Azure? Поскольку это должен быть стандартный, а не базовый LB, который кажется непомерно дорогим. Надеюсь, я что-то упустил. Любая помощь будет принята с благодарностью. Обратите внимание, что я поделился только соответствующим кодом из моего проекта terraform. Если потребуется больше кода, дайте мне знать (я не смог добавить динамический блок в тег вопроса, потому что у меня слишком мало репутации). Спасибо, - Сэм Качар

2 ответа

Решение

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

Попытки использовать ссылку each.value терпели неудачу. Это вызывало ошибку, что-то вроде each.value нужно использовать с for_each... Что меня расстраивало, поскольку for_each было всего на 2 строки выше, где я пытался использовать / ссылаться на него. Более того, в этой ошибке было создано 3 сообщения об ошибках, поэтому он выполнял итерацию с использованием for_each. По какой-то причине он не мог извлекать значения с помощью each.value.

Код, который в итоге работал для моих зон доступности LB / Azure, был следующим (подсказка, пришлось использовать опцию итератора):

resource "azurerm_lb" "lb" {
  name                = "externallb"
  location            = "${azurerm_resource_group.rg.location}"
  resource_group_name = "${azurerm_resource_group.rg.name}"
  sku                 = "standard" #standard SKU needed to support zones
  dynamic "frontend_ip_configuration" {
    iterator = pub
    for_each = azurerm_public_ip.pip 
    content {
      name                 = "config_${pub.value.ip_address}"
      public_ip_address_id = pub.value.id
    }

  }
}

....

resource "azurerm_lb_nat_rule" "lbnr" {
  count                          = "${var.nblinuxvms}"
  resource_group_name            = "${azurerm_resource_group.rg.name}"
  loadbalancer_id                = "${azurerm_lb.lb.id}"
  name                           = "SSHHost${count.index}"
  protocol                       = "Tcp"
  frontend_port                  = "${2200 + count.index}"
  backend_port                   = 22
  frontend_ip_configuration_name = "config_${azurerm_public_ip.pip[count.index].ip_address}"
}

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

Что касается вашего последнего утверждения о том, что это не версия 11, и мне не нужен весь синтаксис интерполяции, я работаю над его очисткой. Это одна из моих задач в моем списке дел, которую мне еще нужно выполнить, поскольку я завершаю этот проект для полнофункционального модуля виртуальной машины. Я бы сэкономил массу времени, если бы в вычислительном модуле реестра terraform были зоны Azure, но при создании всего этого кода мне пришлось выучить язык намного лучше, чем просто позвонить в реестр.

Как я уже сказал выше, еще раз спасибо за публикацию ответа, он подтвердил, что я шел правильным путем. Надеюсь, что все это время я помогал кому-то другому, если он столкнется с подобной проблемой. Просто обратите внимание на всех, кто это читает: у меня есть блок azurerm_public_ip, который создает столько PIP, сколько необходимо для виртуальных машин и LB. Если кто-то хочет, чтобы я добавил этот код, я могу. Просто напишите мне сообщение или прокомментируйте мой пост.

Ура, - Сам Качар

Я чувствую, что то, что вы пытаетесь сделать, имеет смысл и должно быть возможным. Несколько замечаний:

  • В рамках for_each блок, вы можете использовать each.valueдля доступа к значению (в данном случае это общедоступный объект ip). См for_each документации для деталей
  • ip_address относится к фактическому назначению ip, а не к объекту
  • count недоступен в for_each блоков, поэтому имя frontend_ip_configuration блоки должны выводиться напрямую из публичного объекта ip.

Учитывая вышеизложенное, вы можете попробовать что-то вроде этого (не проверено!):

resource "azurerm_lb_nat_rule" "lbnr" {
  count                          = "${var.nblinuxvms}"
  ...
  frontend_ip_configuration_name = "config_${azurerm_public_ip[count].name}"
}
dynamic "frontend_ip_configuration" {
   for_each = "${azurerm_public_ip.pip}"
   content{
     name                 = "config_${each.value.name}" 
     public_ip_address_id = "${each.value.id}"
  }

Я предполагаю, что вы используете terraform 0.12, учитывая for_eachне был доступен в 0.11. Синтаксис подробной интерполяции, который вы используете, уже устарел в последней версии, лучше используйте новую:

resource "azurerm_lb_nat_rule" "lbnr" {
  count                          = var.nblinuxvms
  ...
  frontend_ip_configuration_name = "config_${azurerm_public_ip[count].name}"
}
dynamic "frontend_ip_configuration" {
   for_each = azurerm_public_ip.pip
   content{
     name                 = "config_${each.value.name}" 
     public_ip_address_id = each.value.id
}
Другие вопросы по тегам