Terraform: как запустить remote-exec более одного раза?

Я заметил, что terraform будет запускать" file"," remote-exec "или" local-exec " на ресурсах только один раз. После того, как ресурс подготовлен, если команды в "remote-exec" изменены или файл из "файла" поставщика изменен, terraform не будет вносить никаких изменений в экземпляр. Итак, как я могу заставить terraform запускать provisioner "file", "remote-exec" или "local-exec" каждый раз, когда я запускаю terraform?

для получения более подробной информации:

часто я если ресурс был частично подготовлен из-за ошибки "remote-exec", terraform останавливается (в основном из-за ввода неправильных команд во время написания сценария). Запуск terraform снова после этого приведет к уничтожению ранее созданного ресурса и заставит terraform создать новый ресурс с нуля. Это также единственный способ, которым я могу запустить "remote-exec" дважды на ресурсе... создав его с нуля.

это действительно недостаток terraform как в отличие от ansible, который может выполнять ту же самую работу, что и terraform, за исключением того, что он полностью идемпотентен. При использовании Ansible с такими задачами, как" ec2"," shell "и" copy", я могу достичь тех же задач, что и terraform, только каждая из этих задач будет идемпотентной. Ansible автоматически распознает, когда ему не нужно вносить изменения, где он это делает, и из-за этого он может подобрать, где неудачный ansible-playbook остановился, не разрушая все и начиная с нуля. Terraform не хватает этого особенность.

для справки вот простой блок ресурсов terraform для экземпляра ec2, который использует как" remote-exec", так и" file " provisioners:

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 ответов


на документы Terraform по подготовке явно, что он рассматривает использование provisioners для базовой начальной загрузки как задачу только один раз и что он не должен использоваться в качестве замены для надлежащего инструмента управления конфигурацией, такого как Ansible:

поставщики запускаются только при создании ресурса. Они не замена для управления конфигурацией и изменения программного обеспечения уже запущенный сервер, и вместо этого просто подразумевается как способ загрузочный сервер. Для управления конфигурацией следует использовать Подготовка Terraform для вызова реального управления конфигурацией решение.

и

Если ресурс успешно создается, но не в положение, Terraform ошибется и пометит ресурс как "испорченный"." Ресурс это испорчено было физически создано, но не может быть рассмотрено безопасно использовать после сбоя подготовки.

при создании ваш следующий план выполнения, Terraform удалит любые испорченные ресурсы и создать новые ресурсы, пытаясь обеспечить снова. Он не пытается перезапустить подготовку на том же ресурс, потому что он не гарантирует безопасность.

Terraform автоматически не откатывается и не уничтожает ресурс во время применения, когда происходит сбой, потому что это пойдет против плана выполнения: план выполнения сказал бы ресурс будет создан, но не не сказать, что он будет удален. Но если вы создаете план выполнения с испорченным ресурсом, план будет четко указано, что ресурс будет уничтожен, потому что он испорченный.

подготовка важна для возможности загрузки экземпляров. Как еще одно напоминание, это не замена конфигурации управление. Он предназначен для простой загрузки машин. Если вы используете управление конфигурацией, вы должны использовать подготовку как способ бутстрапа утилита управления конфигурацией.

рассматривайте provisioners как сродни скрипту пользовательских данных EC2 в том, что он запускается только один раз при создании, и если он терпит неудачу, вам нужно уничтожить экземпляр и повторить попытку.

преимущества этого заключается в том, что Terraform не нужно иметь никаких знаний о том, как сделать изменения идемпотентными в операционной системе, поскольку Terraform работает на уровне выше, чем сам экземпляр, и больше при подготовке всех данных центр.

Если вам нужно больше гибкости, чем это, то рассмотрите либо использование Terraform для вызова системы управления конфигурацией, чтобы правильно подготовить экземпляр (а затем разрешить повторные попытки в этом случае, если это не удастся, отделенный от этапа подготовки Terraform), либо использование инструмента оркестровки, такого как Дженкинс, чтобы обернуть Terraform и альтернативный инструмент управления конфигурацией, такой как Ansible.

еще один вариант - идти больше по маршруту неизменяемого инфраструктура и использование упаковщик чтобы создать AMI с помощью Ansible или другого инструмента, а затем просто использовать Terraform для развертывания AMI, как есть, без необходимости дальнейшего предоставления экземпляра.


наткнулся на этот поток в моих поисках и в конечном итоге нашел решение:

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"
  }
}

вы можете использовать UUID (), который уникален для каждого запуска terraform, чтобы вызвать нулевой ресурс или поставщик.


можно использовать taint команда пометить ресурс как испорченный, заставляя его быть уничтоженным и воссозданным при следующем применении.