Terraform 在应用时触发循环错误

Terraform fires Cycle error when applying

我正在尝试使用 terraform 构建一个 galera 集群。为此,我需要使用节点 ip 渲染 galera 配置,所以我使用了一个文件模板。

应用时,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")
    }

  }



}

您确实尝试在 resource "hcloud_server" "galera_node" 中使用 data.template_file.galera_node_config 并在 data.template_file 中使用 hcloud_server.galera_node

要避免这个问题:

  1. 从您的 hcloud_server.galera_node
  2. 中删除供应商“文件”
  3. 将此供应商“文件”移动到新的 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]
}

这里的问题是您有多个相互依赖的节点,因此 Terraform 没有有效的顺序来创建它们:它们必须在创建任何其他节点之前全部创建。

解决这个问题需要不同的方法。为此有几个不同的选项,但似乎最接近您已经尝试的选项是使用特殊资源类型 null_resource 将配置分解为一个单独的资源,毕竟 Terraform 只能在该资源上工作的 hcloud_server 个实例已准备就绪。

另请注意,template_file 数据源已弃用,取而代之的是 the templatefile function,因此这是一个通过使用函数来简化配置的好机会。

这两个变化共同导致:

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 每次配置文件以任何方式更改时它都必须重新 运行 配置程序,例如,这可能是因为您添加了新节点:然后将重新配置所有现有节点以在其配置中包含该附加节点。

Provisioners are considered a last resort in the Terraform documentation, but in this particular case the alternatives would likely be considerably more complicated. A typical non-provisioner answer to this would be to use a service discovery system where each node can register itself on startup and then discover the other nodes, for example with HashiCorp Consul 的服务目录。但是,除非您的基础架构中有很多类似的用例,它们都可以共享 Consul 集群,否则与仅使用供应商相比,必须 运行 另一项服务可能是不合理的成本。