捕获Terraform配置器输出?

jiv*_*key 7 terraform

用例

尝试配置(Docker Swarm或Consul)集群,其中首先在一个节点上初始化集群,该节点生成一些令牌,然后需要由加入集群的其他节点使用.关键是节点1和2不应该尝试加入集群,直到节点0生成了连接密钥.

例如.在节点0上,运行docker swarm init ...将返回一个连接令牌.然后在节点1和2上,您需要将该令牌传递给相同的命令,例如docker swarm init ${JOIN_TOKEN} ${NODE_0_IP_ADDRESS}:{SOME_PORT}.而魔术,你有一个整洁的小集群......

试图到目前为止

  • 尝试使用安装的AWS SDK初始化所有节点,并在S3上存储来自节点0的连接密钥,然后在其他节点上获取该连接密钥.这是通过带有'remote-exec'配置程序的null_resource完成的.由于Terraform并行执行的方式,有一些类型条件,并且可预测节点1和2经常尝试从S3获取一个尚未存在的密钥(例如,节点0还没有完成它的东西).

  • 尝试使用'local-exec'配置程序SSH到节点0并捕获其连接键输出.这种方法效果不佳,或者我这样做很糟糕.


我已经阅读了文档.并且堆栈溢出.和Github一样,这个问题确实很长.彻底.如果这已经在其他地方解决了,链接赞赏!


PS - 这与此问题直接相关并且是此问题的较小子集,但是想要重新询问它以便集中解决问题的范围.

小智 14

您可以将输出重定向到文件:

resource "null_resource" "shell" {

  provisioner "local-exec" {
    command = "uptime 2>stderr >stdout; echo $? >exitstatus"
  }
}
Run Code Online (Sandbox Code Playgroud)

然后读取stdout,stderr和exitstatus文件用local_file

问题是如果文件消失,那么terraform apply将失败.

我通过使用外部数据源读取文件并将结果存储在null_resource触发器(!)中来解决方法

resource "null_resource" "contents" {
  triggers = {
    stdout     = "${data.external.read.result["stdout"]}"
    stderr     = "${data.external.read.result["stderr"]}"
    exitstatus = "${data.external.read.result["exitstatus"]}"
  }

  lifecycle {
    ignore_changes = [
      "triggers",
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

然后最后我可以使用/输出那些:

output "stdout" {
  value = "${chomp(null_resource.contents.triggers["stdout"])}"
}
Run Code Online (Sandbox Code Playgroud)

有关完整实施,请参阅模块https://github.com/matti/terraform-shell-resource


sha*_*unc 11

您可以使用外部数据:

data "external" "docker_token" {
  program = ["/bin/bash", "-c" "echo \"{\\\"token\\\":\\\"$(docker swarm init...)\\\"}\""]
}
Run Code Online (Sandbox Code Playgroud)

然后令牌将作为 提供data.external.docker_token.result.token。如果需要传入参数,可以使用脚本(例如相对于path.module)。看

了解详情。(链接更新感谢@TinyTiger)


nbe*_*ing 5

当我问自己同样的问题时,“我可以使用来自供应商的输出来输入另一个资源的变量吗?”,我去了源寻求答案。

此时,供应商的结果只是流式传输到 terraform 的标准输出,而永远不会被捕获。

鉴于您在两个节点上都运行远程供应商,并且您正在尝试从 S3 访问值 - 顺便说一下,我同意这种方法,我也会这样做 - 您可能需要做的是处理脚本中的竞争条件用sleep命令,或通过调度脚本来后来与运行at或cron或类似的调度系统。

通常,Terraform 希望预先访问所有变量,或者作为提供程序的结果访问所有变量。在 Terraform 中,供应商不一定被视为一流的。我不是核心团队的成员,所以我不能说为什么,但我的猜测是,除了成功或失败之外,忽略配置器结果会降低复杂性,因为配置器只是脚本,因此它们的结果通常是非结构化的。

如果您需要更多增强的功能来设置您的实例,我建议使用专用工具,如 Ansible、Chef、Puppet 等。Terraform 的重点实际上是基础设施,而不是软件组件。

  • 得出了与您上面阐述的相同的结论 - 我认为 terraform 更适合基础设施组件(仅),而最好将配置和引导工具一起留给更适合处理该问题的工具,例如 Ansible。谢谢! (2认同)