我正在使用Terraform在DigitalOcean上设置运行Consul的多个水滴。也许我遗漏了一些基本的东西,但为它们提供正确的配置似乎非常困难。
resource "digitalocean_droplet" "prime" {
count = 3
image = "${data.digitalocean_image.prime.image}"
name = "${format("%s-%02d-%s", "prime", count.index + 1, var.region)}"
private_networking = true
# ...
}
每台机器都有两个网络接口 - 公共和私有。使用此设置,似乎有必要提供bind_addr
指向每个Droplet的私有IP地址 - 否则consul将退出并显示有多个私有(?!)地址的错误。
最直接的解决方案是为每台计算机配置一个配置文件,在每种情况下几乎相同,但bind_addr
字段的值不同,如下所示:
{
"server": true,
"data_dir": "/var/consul/data",
"ui": true,
"bind_addr": "${ private_ipv4_address }"
}
不是模板的用途吗?我无法弄清楚如何以这种方式使用它们。在定义模板时,模板的变量似乎只能提供一次:
data "template_file" "consul-config" {
template = "${file("templates/consul-config.json.tpl")}"
vars {
private_ipv4_address = "10.0.0.1" # At this point the real address is not known
}
}
resource "digitalocean_droplet" "prime" {
...
provisioner "file" {
content = "${data.template_file.consul-config.rendered}"
destination = "/etc/consul.d/server.json"
# At this point the address is known: ${ self.private_ipv4_address },
# but is it possible to pass it to the template?
}
}
我尝试将数据块嵌套在资源块中,但之后我收到了类似的错误:
Error: resource 'digitalocean_droplet.prime' provisioner file (#7): unknown resource 'data.template_file.consul-config' referenced in variable data.template_file.consul-config.rendered
我目前使用的解决方法是将配置拆分为两部分(服务器和自定义),并在文件配置器中内联自定义内容:
resource "digitalocean_droplet" "prime" {
# ...
provisioner "file" {
content = "${data.template_file.consul-config.rendered}"
destination = "/etc/consul.d/server.json"
}
# This is a custom configuration for each particular droplet
provisioner "file" {
content = "{ \"bind_addr\": \"${ self.ipv4_address_private }\", \"bootstrap\": ${ count.index == 0 } }"
destination = "/etc/consul.d/custom.json"
}
}
它有效,但可读性受到阻碍有几个原因:
所有报价必须转义
一切都必须在单行(?)
没有语法突出显示或来自文本编辑器的类似帮助
或者我考虑过使用外部程序(如envsubst
)来渲染模板或将built in format
function与file function一起使用,但每个程序看起来都很麻烦。
有没有直接的方式来达到我想要的目的?
答案 0 :(得分:2)
您是否尝试过使用写入模块?
这可能是一个很好的起点: https://blog.gruntwork.io/how-to-create-reusable-infrastructure-with-terraform-modules-25526d65f73d
答案 1 :(得分:1)
模板旨在从Terraform中获取值(无论是来自变量文件,本地变量,数据资源等),并将其插入模板文件中。通常,我已经看到生成的文件是将由您的最终资源(用于AWS的EC2实例,用于DigitalOcean的Droplet)运行的脚本。
模块(在另一个答案中提到)用于通过单个入口点设置资源(例如服务器,负载均衡器,一些网络资源)的集合。我相信您是正确的,它不适用于您的情况。
我要完成与您想要的操作类似的方法(在创建资源后获取IP地址)是模板化脚本并将其提供给您的Droplet。然后让该脚本询问小程序的IP是什么。因此,您需要在Droplet中定义一个user_data资源:
resource "digitalocean_droplet" "prime" {
user_data = "${data.template_file.some_script.rendered}"
}
然后您还有一个数据模板:
data "template_file" "consul-config" {
template = "${file("templates/consul-config.json.tpl")}"
vars {
# Define Script Variables here, excluding IP
}
}
将其渲染到shell(或python,perl等)脚本中
# Get networking details
ifconfig | #pipe to function of your choice and format results as you please.
# Do stuff to configure server.
答案 2 :(得分:0)
已经一年多了……也许您已经找到了解决问题的方法。
我绝不是Terraform的专家,而是在这种特殊情况下,因为您需要的信息在小滴中...您可以将脚本传递给小滴,以创建所需的配置...
$ addr=`ip addr show eth1 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1`
$ tee consul.json <<EOF
{
"server": true,
"data_dir": "/var/consul/data",
"ui": true,
"bind_addr": "$addr"
}
EOF
$ echo 'YES!!' ## LOL
这将用作user_data,remote-exec提供者等...