terraform - Terraform 应用时触发循环错误
问题描述
我正在尝试使用 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")
}
}
}
解决方案
这里的问题是您有多个相互依赖的节点,因此 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 文档中, Provisioner 被认为是最后的手段,但在这种特殊情况下,替代方案可能要复杂得多。一个典型的非供应商解决方案是使用服务发现系统,其中每个节点都可以在启动时注册自己,然后发现其他节点,例如使用HashiCorp Consul的服务目录。但是,除非您的基础设施中有许多类似的用例都可以共享 Consul 集群,否则与仅使用配置器相比,必须运行另一个服务可能是不合理的成本。
推荐阅读
- php - 如何在codeigniter中获取用户列表?
- sql-server - 无法在 azure sql 中为 master 数据库创建主密钥
- python - 检查导入到交互式控制台的模块
- blockchain - 如果被投票的节点成为提议者,投票者会得到钱吗
- ios - 键盘消失时增加Tableview的高度?
- linux - shell脚本中的%和%%有什么区别?
- powershell - Powershell 查询数据库并将结果存储在变量中
- sql-server - Talend Open Studio:SQL Server 2017 连接问题
- ruby-on-rails - 用于在 rails 中的每个命名空间中通知的 Action Cable
- javascript - 如何将对象数组内的嵌套数组中的数据推送到新数组?同时保持其嵌套结构