首页 文章

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

提问于
浏览
8

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

For more details:

由于“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"
}

}

3 回答

  • 2

    Terraform docs on provisioning明确表示它认为使用供应商进行基本引导作为一次性任务,并且它不应该用作适当的配置管理工具(如Ansible)的替代品:

    只有在创建资源时才运行配置程序 . 它们不是配置管理的替代品,也不是更改已经运行的服务器的软件,而只是作为引导服务器的一种方式 . 对于配置管理,您应该使用Terraform配置来调用真实的配置管理解决方案 .

    如果资源成功创建但在配置期间失败,Terraform将发生错误并将资源标记为“受污染” . 被物理创建的资源已被物理创建,但由于配置失败,因此无法认为是安全的 . 当您生成下一个执行计划时,Terraform将删除任何受污染的资源并创建新资源,尝试再次进行配置 . 它不会尝试在同一资源上重新启动配置,因为它不能保证安全 . 当故障发生时,Terraform不会在应用期间自动回滚并销毁资源,因为这会违反执行计划:执行计划会说创建资源,但不会说它将被删除 . 但是,如果您使用受污染的资源创建执行计划,该计划将明确指出资源将被销毁,因为它已被污染 . 配置对于能够引导实例很重要 . 另外提醒一下,它不是配置管理的替代品 . 它只是为了引导机器 . 如果使用配置管理,则应使用配置作为引导配置管理实用程序的方法 .

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

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

    如果您需要比此更多的灵活性,那么考虑使用Terraform调用配置管理系统来正确配置实例(然后允许重试,如果失败,与Terraform配置阶段分离)或使用诸如Jenkins之类的编排工具包装Terraform和替代配置管理工具,如Ansible .

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

  • 6

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

    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()来触发空资源或配置器 .

  • 17

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

相关问题