Terraform 捕获地形供应器输出?

Terraform 捕获地形供应器输出?,terraform,Terraform,用例 尝试配置Docker Swarm或Consor群集,其中初始化群集首先发生在一个节点上,这会生成一些令牌,然后需要由加入群集的其他节点使用。关键是节点1和2不应该尝试加入集群,直到节点0生成了加入密钥 例如,在节点0上,运行docker swarm init。。。将返回一个加入令牌。然后在节点1和2上,您需要将该令牌传递给相同的命令,如docker swarm init${JOIN_token}${NODE_0_IP_ADDRESS}:{SOME_PORT}。还有魔法,你有一个整洁的小簇

用例

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

例如,在节点0上,运行docker swarm init。。。将返回一个加入令牌。然后在节点1和2上,您需要将该令牌传递给相同的命令,如docker swarm init${JOIN_token}${NODE_0_IP_ADDRESS}:{SOME_PORT}。还有魔法,你有一个整洁的小簇

迄今为止的尝试

尝试在安装了AWS SDK的情况下初始化所有节点,并将节点0中的连接密钥存储在S3上,然后在其他节点上获取该连接密钥。这是通过带有“remote exec”供应器的空_资源完成的。由于Terraform并行执行事物的方式,存在racy类型的条件,可以预见的是节点1和2经常尝试从S3获取一个尚未存在的密钥,例如节点0尚未完成它的工作

已尝试使用“local exec”provisioner以SSH方式连接到节点0并捕获其连接密钥输出。这不管用,或者我做得很烂

我看过文件了。和堆栈溢出。还有Github问题,比如。非常如果这已经在其他地方解决了,链接将不胜感激


PS-这与直接相关,并且是一个较小的子集,但为了集中问题的范围,我想重新询问它。

当我问自己同样的问题时,我可以使用provisioner的输出输入到另一个资源的变量吗?我去源代码寻求答案

此时此刻,供应器结果被简单地流式传输到terraform的标准输出,而从未被捕获

假设您在两个节点上都运行远程供应器,并且尝试从S3访问值-顺便说一句,我同意这种方法,我也会这么做-您可能需要做的是使用sleep命令处理脚本中的竞争条件,或者通过调度脚本,以便稍后使用at或cron或类似的调度系统运行

一般来说,Terraform希望预先访问所有变量,或者作为提供者的结果访问所有变量。在地形中,供给者不一定被视为第一流。我不在核心团队中,所以我不能说为什么,但我的猜测是,忽略provisioner结果会降低复杂性,而不仅仅是成功或失败,因为provisioner只是脚本,所以它们的结果通常是非结构化的

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

使用此工具,您可以确保先创建一个资源,再创建另一个资源

这里有一个关于我如何创建我的领事集群的不完整的例子,只是给你一个想法

resource "aws_instance" "consul_1" {
    user_data = <<EOF
    #cloud-config
    runcmd:
    - 'docker pull consul:0.7.5'
    - 'docker run -d -v /etc/localtime:/etc/localtime:ro -v $(pwd)/consul-data:/consul/data --restart=unless-stopped --net=host consul:0.7.5 agent -server -advertise=${self.private_ip} -bootstrap-expect=2 -datacenter=wordpress -log-level=info -data-dir=/consul/data'
    EOF

}

resource "aws_instance" "consul_2" {

    depends_on = ["aws_instance.consul_1"]

    user_data = <<EOF
    #cloud-config
    runcmd:
    - 'docker pull consul:0.7.5'
    - 'docker run -d -v /etc/localtime:/etc/localtime:ro -v $(pwd)/consul-data:/consul/data --restart=unless-stopped --net=host consul:0.7.5 agent -server -advertise=${self.private_ip} -retry-join=${aws_instance.consul_1.private_ip} -datacenter=wordpress -log-level=info -data-dir=/consul/data'
    EOF

 }
对于docker swarm设置,我认为它超出了Terraform的范围,我认为应该这样做,因为令牌不是您正在创建的基础设施的属性。所以我同意,您可以尝试使用Ansible或Chef之类的工具来实现该设置


但是无论如何,如果这个例子帮助你设置你的Concur集群,我认为你只需要将Concur配置为docker swarm后端。

更简单的解决方案是自己提供令牌


创建ACL令牌时,只需传入ID值,Consor就会使用该ID值,而不是随机生成一个。

您可以有效地将节点0的docker swarm init步骤作为Terraform外部数据源运行,并让它返回JSON。使剩余节点的设置依赖于此步骤,并参考外部数据源生成的连接令牌

-是基于Terraform的基础设施的轻量级供应器,可以处理您的情况。下面是aws ec2实例的示例

假设Consor集群有3个ec2实例:node0、node1和node2。第一个节点0是我们从中获取令牌并将其保存在S3桶中的位置。另外两个稍后从S3加载令牌

$ nano aws_instance.node0.sparrowfile 

#!/usr/bin/env perl6

# have not checked this command, but that's the idea ...
bash "docker swarm init | aws s3 cp - s3://alexey-bucket/stream.txt"

$ nano aws_instance.node1.sparrowfile

#!/usr/bin/env perl6

my $i=0;
my $token;

try {

  while True {
    my $s3-token = run 'aws', 's3', 'cp', 's3://alexey-bucket/stream.txt', '-', :out;
    $token = $s3-token.out.lines[0];
    $s3-token.out.close;
    last if $i++ > 8 or $token;
    say "retry num $i ...";
    sleep 2*$i;
  }

  CATCH { { .resume } }

}

die "we have not succeed in fetching token" unless $token;

bash "docker swarm init $token";

$ nano aws_instance.node2.sparrowfile - the same setup as for node1


$ terrafrom apply # bootstrap infrastructure

$ sparrowform --ssh_private_key=~/.ssh/aws.pub --ssh_user=ec2-user # run provisioning on node0, node1, node2

请注意,我是工具作者。

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

resource "null_resource" "shell" {

  provisioner "local-exec" {
    command = "uptime 2>stderr >stdout; echo $? >exitstatus"
  }
}
然后用本地_文件读取stdout、stderr和exitstatus文件

问题是,如果文件消失,terraform应用将失败

在terraform 0.11中,我通过读取带有外部数据源的文件并将结果存储在一个null_资源触发器中来解决问题

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",
    ]
  }
}
但在0.12中,这可以替换为文件

最后,我可以使用/输出以下内容:

output "stdout" {
  value = "${chomp(null_resource.contents.triggers["stdout"])}"
}

有关完整实施的信息,请参见模块

您可以使用外部数据:

data "external" "docker_token" {
  program = ["/bin/bash", "-c" "echo \"{\\\"token\\\":\\\"$(docker swarm init...)\\\"}\""]
}
然后令牌将作为data.external.docker\u token.result.token可用。
如果需要传入参数,可以使用脚本,例如相对于path.module。有关详细信息,请参阅。

感谢您发布如何处理领事的帖子
设置。我有点同意docker swarm的设置可能不在Terraform的范围内,但它与设置一个Consor集群是一样的,所以如果引导Consor是有意义的,那么我会说引导docker swarm也是有意义的。还在考虑。。。此外,不幸的是,最新的Docker Swarm从1.13版开始,其后端不再可配置,无法替代Swarm自己的分布式状态存储。无论如何,感谢您的回复。得出了与您上面阐述的相同的结论-我认为terraform更适合于基础架构组件,而将资源调配和引导工作一起留给一个更适合像Ansible这样处理的工具则更好。谢谢