Terraform выдает ошибку цикла при применении

Я пытаюсь построить кластер galera, используя terraform. Для этого мне нужно отобразить конфигурацию galera с IP-адресом узлов, поэтому я использую шаблон файла.

При применении terraform выдает ошибку

Error: Cycle: data.template_file.galera_node_config, hcloud_server.galera_node

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

Как я могу это обойти?

Спасибо

galera_node.tf
data "template_file" "galera_node_config" {
  template = file("sys/etc/mysql/mariadb.conf/galera.cnf")

  vars = {
    galera_node0 = hcloud_server.galera_node[0].ipv4_address
    galera_node1 = hcloud_server.galera_node[1].ipv4_address
    galera_node2 = hcloud_server.galera_node[2].ipv4_address
    curnode_ip = hcloud_server.galera_node[count.index].ipv4_address
    curnode = hcloud_server.galera_node[count.index].id
    }
}


resource "hcloud_server" "galera_node" {
  count       = var.galera_nodes
  name        = "galera-${count.index}"
  image       = var.os_type
  server_type = var.server_type
  location    = var.location
  ssh_keys    = [hcloud_ssh_key.default.id]

  labels = {
    type = "cluster"
  }

  user_data = file("galera_cluster.sh")

  provisioner "file" {
    content     = data.template_file.galera_node_config.rendered
    destination = "/tmp/galera_cnf"
    connection {
      type        = "ssh"
      user        = "root"
      host = self.ipv4_address
      private_key = file("~/.ssh/id_rsa")
    }

  }



}

person ppk    schedule 11.12.2020    source источник


Ответы (2)


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

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

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

Оба эти изменения вместе приводят к следующему:

resource "hcloud_server" "galera_node" {
  count       = var.galera_nodes
  name        = "galera-${count.index}"
  image       = var.os_type
  server_type = var.server_type
  location    = var.location
  ssh_keys    = [hcloud_ssh_key.default.id]

  labels = {
    type = "cluster"
  }

  user_data = file("galera_cluster.sh")
}

resource "null_resource" "galera_config" {
  count = length(hcloud_server.galera_node)

  triggers = {
    config_file = templatefile("${path.module}/sys/etc/mysql/mariadb.conf/galera.cnf", {
      all_addresses = hcloud_server.galera_node[*].ipv4_address
      this_address  = hcloud_server.galera_node[count.index].ipv4_address
      this_id       = hcloud_server.galera_node[count.index].id
    })
  }

  provisioner "file" {
    content     = self.triggers.config_file
    destination = "/tmp/galera_cnf"
    connection {
      type        = "ssh"
      user        = "root"
      host        = hcloud_server.galera_node[count.index].ipv4_address
      private_key = file("~/.ssh/id_rsa")
    }
  }
}

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

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

person Martin Atkins    schedule 11.12.2020
comment
К сожалению, приходится использовать устаревшую версию :( - person ppk; 11.12.2020

Вы действительно пытаетесь использовать data.template_file.galera_node_config внутри своего resource "hcloud_server" "galera_node" и использовать hcloud_server.galera_node в своем data.template_file.

Чтобы избежать этой проблемы:

  1. Удалите файл Provisioner с вашего hcloud_server.galera_node
  2. Переместите этот файл инициатора в новый null_resource, например. как это:
resource "null_resource" template_upload {
  count = var.galera_nodes
  provisioner "file" {
    content     = data.template_file.galera_node_config.rendered
    destination = "/tmp/galera_cnf"
    connection {
      type        = "ssh"
      user        = "root"
      host = hcloud_server.galera_nodes[count.index].ipv4_address
      private_key = file("~/.ssh/id_rsa")
    }
depends_on = [hcloud_server.galera_node]
}
person Fedor Petrov    schedule 11.12.2020
comment
Конечно, мне нужно это отредактировать. Нам также нужно добавить счетчик к этому новому ресурсу. - person Fedor Petrov; 11.12.2020
comment
Спасибо, мне помогли оба подхода. - person ppk; 11.12.2020