Terraform:如何多次运行remote-exec?

时间:2016-08-21 22:13:34

标签: ansible terraform idempotent

我注意到terraform只会在资源上运行一次“file”,“remote-exec”或“local-exec”。一旦资源被配置,如果“remote-exec”中的命令被更改或者来自供应者“file”的文件被更改,则terraform将不会对实例进行任何更改。那么每次运行terraform时,如何让terraform运行供应商“file”,“remote-exec”或“local-exec”?

有关详细信息:

由于“remote-exec”错误导致terraform停止(部分由于我在编写脚本时输入了错误的命令),我经常部署资源。在此之后再次运行terraform将导致先前创建的资源被破坏并强制terraform从头开始创建新资源。这也是我可以在资源上运行两次“remote-exec”的唯一方法......从头开始创建它。

对于terraform来说,这确实是一个缺点,而不是ansible,它可以做与terraform完全相同的工作,除了它完全是幂等的。当使用Ansible执行诸如“ec2”,“shell”和“copy”之类的任务时,我可以完成与terraform相同的任务,只有每个任务都是幂等的。 Ansible会自动识别何时不需要进行更改,它会在何处进行更改,因此可以自动识别失败的ansible-playbook停止的位置而不会破坏所有内容并从头开始。 Terraform缺乏此功能。

这里是一个简单的terraform资源块,供ec2实例使用“remote-exec”和“file”配置器:

resource "aws_instance" "test" {

count = ${var.amt}
ami = "ami-2d39803a"
instance_type = "t2.micro"
key_name = "ansible_aws"
tags {
  name = "test${count.index}"
}

#creates ssh connection to consul servers
connection {
  user = "ubuntu"
  private_key="${file("/home/ubuntu/.ssh/id_rsa")}"
  agent = true
  timeout = "3m"
} 

provisioner "remote-exec" {
  inline = [<<EOF

    sudo apt-get update
    sudo apt-get install curl unzip
    echo hi

  EOF
  ]
}

#copying a file over
provisioner "file" {
  source = "scripts/test.txt"
  destination = "/path/to/file/test.txt"
}

}

4 个答案:

答案 0 :(得分:19)

在我的搜索中遇到了这个帖子并最终找到了解决方案:

resource "null_resource" "ansible" {

  triggers {
    key = "${uuid()}"
  }

  provisioner "local-exec" {
  command = "ansible-playbook -i /usr/local/bin/terraform-inventory -u ubuntu playbook.yml --private-key=/home/user/.ssh/aws_user.pem -u ubuntu"
  }
}

您可以使用每个terraform运行独有的uuid()来触发空资源或配置器。

答案 1 :(得分:6)

Terraform docs on provisioning显式地认为使用供应商进行基本引导作为一次性任务,并且它不应该用作替代适当的配置管理工具,例如Ansible:

  

仅在创建资源时运行配置程序。他们不是   替换配置管理和更改软件   一个已经运行的服务器,而只是作为一种方式   引导服务器。对于配置管理,您应该使用   Terraform配置以调用实际配置管理   溶液

  

如果资源成功创建但在提供期间失败,   Terraform将出错并将资源标记为“受污染”。资源   被污染的是物理创造的,但不能被考虑   由于配置失败,因此可以安全使用。

     

当您生成下一个执行计划时,Terraform将删除任何计划   污染资源并创造新资源,试图提供资源   再次。它不会尝试重新启动配置   资源,因为它不能保证安全。

     

Terraform不会自动回滚并销毁资源   在失败发生时的申请期间,因为那会发生   反对执行计划:执行计划会说a   将创建资源,但不会说它将被删除。   但是,如果您使用受污染的资源创建执行计划,则计划   将清楚地说明资源将被销毁,因为它是   污点。

     

配置对于能够引导实例非常重要。如   另一个提醒,它不是配置的替代品   管理。它只是为了引导机器。如果你使用   配置管理,您应该使用配置作为一种方式   引导配置管理实用程序。

将配置程序视为类似于EC2用户数据脚本,因为它只在创建时运行一次,如果失败,则需要销毁该实例并重试。

这样做的好处是,Terraform不需要知道如何在操作系统上使更改具有幂等性,因为Terraform的工作级别高于实例本身,而且更多的是配置整个数据中心。 / p>

如果您需要比此更多的灵活性,那么考虑使用Terraform调用配置管理系统来正确配置实例(如果失败则允许重试,与Terraform配置阶段分离)或使用业务流程工具例如Jenkins用于包装Terraform和另一种配置管理工具,例如Ansible。

另一个选择是更多地沿着不可变基础设施的路线,并使用Packer使用Ansible或其他工具创建AMI,然后只需使用Terraform按原样部署AMI,而无需进一步提供实例。

答案 2 :(得分:2)

您可以使用taint命令将资源标记为受污染,强制将其销毁并在下次应用时重新创建。

答案 3 :(得分:0)

Chris Holmes 的类似答案,但使用时间戳,您需要从 Chris 的答案中删除 UUID 或 timestamp() 周围的 ${""},因为现在您将收到以下消息:< /p> <块引用>

警告:不推荐使用仅插值表达式

除非您使用 Terraform 0.11 或更早版本。

clip.resize(1920,1080)