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
。
要避免这个问题:
- 从您的 hcloud_server.galera_node
中删除供应商“文件”
- 将此供应商“文件”移动到新的 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 集群,否则与仅使用供应商相比,必须 运行 另一项服务可能是不合理的成本。
我正在尝试使用 terraform 构建一个 galera 集群。为此,我需要使用节点 ip 渲染 galera 配置,所以我使用了一个文件模板。
应用时,terraform 会引发错误
Error: Cycle: data.template_file.galera_node_config, hcloud_server.galera_node
申请的时候好像是循环引用,因为在使用数据模板之前没有创建服务器。
我该如何避免这种情况?
谢谢
galera_node.tfdata "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
。
要避免这个问题:
- 从您的 hcloud_server.galera_node 中删除供应商“文件”
- 将此供应商“文件”移动到新的 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 集群,否则与仅使用供应商相比,必须 运行 另一项服务可能是不合理的成本。