Как я могу автоматически выводить AMI id в цепной упаковщик для терраформирования переменных?

Я использую packer с Ansible provisioner для создания ami и terraform для настройки инфраструктуры с этим ami в качестве источника-несколько похоже на эту статью: http://www.paulstack.co.uk/blog/2016/01/02/building-an-elasticsearch-cluster-in-aws-with-packer-and-terraform

когда команда packer build pack.json завершает успешно я получаю выходной AMI id в этом формате:

eu-central-1: ami-12345678

в моих переменных terraform variables.tf мне нужно указать источник ami id, регион etc. Проблема здесь в том, что я не хочу указывать их вручную или несколько раз. Для региона (который я знаю заранее) это легко, так как я могу использовать переменные среды в обеих ситуациях, но как насчет выходного ami? Есть ли встроенный способ цепочки этих продуктов или какой-то не столь хакерский подход к этому?

EDIT: Hacky подход для всех, кто может быть заинтересован. В этом решении я greping регион aws & ami из вывода Пакера и использовать регулярное выражение в perl для записи результата в :

vars=$(pwd)"/terraform.tfvars"
packer build pack.json | 
    tee /dev/tty | 
    grep -E -o 'w{2}-w+-w{1}: ami-w+' | 
    perl -ne '@parts = split /[:,s]+/, $_; print "aws_amis." . $parts[0] ." = "" . $parts[1] . ""n"' > ${vars}

3 ответов


вы должны рассмотреть с помощью терраформа Исходные Данные на aws_ami. При этом вы можете полагаться на пользовательские теги, установленные на AMI при его создании (например, номер версии или метку времени). Затем в конфигурации Terraform вы можете просто отфильтровать доступные AMIs для этой учетной записи и региона, чтобы получить идентификатор AMI, который вам нужен.

https://www.terraform.io/docs/providers/aws/d/ami.html

data "aws_ami" "nat_ami" {
  most_recent = true
  executable_users = ["self"]
  filter {
    name = "owner-alias"
    values = ["amazon"]
  }
  filter {
    name = "name"
    values = ["amzn-ami-vpc-nat*"]
  }
  name_regex = "^myami-\d{3}"
  owners = ["self"]
}

примечание: в Примере выше (из документов) комбинация фильтров, вероятно, чрезмерна. Вы, наверное, прекрасно обходится примерно так:

data "aws_ami" "image" {
  most_recent = true
  owners = ["self"]
  filter {                       
    name = "tag:Application"     
    values = ["my-app-name"]
  }                              
}

output "ami_id" {
  value = "${data.aws_ami.image.id}"
}

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


" официальным "способом, который рекомендуется Hashicorp, является использование их Атласа продукта в качестве" посредника " между ними. Вы бы использовали постпроцессор Atlas в Packer для записи артефактов (идентификаторы AMI, в вашем случае), а затем использовать на atlas_artifact ресурс в Terraform чтобы снова прочитать идентификаторы для использования в Terraform.

в этом случае вы получите идентификаторы из ресурса, а не передадите их с помощью переменных.

помимо Atlas другие варианты довольно ограничены, а в некоторых случаях и хаки.

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

еще один вариант-написать свой собственный плагин post-processor, который взаимодействует с некоторым программным обеспечением вы уже используете, как альтернатива Atlas. Например, с некоторыми из моих коллег я написал постпроцессор для записи артефактов в качестве метаданных в Buildkite, который мы затем извлекаем с помощью Buildkite API. Это требует написания пользовательского кода в Go.

на момент написания Terraform версия 0.7 все еще находится в разработке, но планируется включить новую функцию, которая позволяет напрямую запрашивать API EC2 для AMIs, который (если он действительно приземляется на 0.7) позволит дополнительно пометить AMI с помощью Packer, а затем найти его непосредственно из EC2, используя эти теги. Это использует сам EC2 в качестве" посредника", что, возможно, менее неудобно, поскольку он уже был задействован в качестве хранилища для AMI.


это подход, который я использую:

  1. оберните вызов упаковщика и получите AMI, проанализировав вывод
  2. используйте проанализированный AMI для создания файлов Terraform, которые предоставляют значение в качестве переменной

это похоже на версию в отредактированном ответе. Более подробно, это может выглядеть так:

сначала создайте файл с именем ami.tf.template:

# "ami.tf" was automatically generated from the template "ami.tf.template".
variable "ami" {
  default     = "${AMI_GENERATED_BY_PACKER}"
  description = "The latest AMI."
}

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

во-вторых, создайте сценарий оболочки оболочки для запуска packer. Вы можете использовать следующие идеи:

# run packer (prints to stdout, but stores the output in a variable)
packer_out=$(packer build packer.json | tee /dev/tty)

# packer prints the id of the generated AMI in its last line
ami=$(echo "$packer_out" | tail -c 30 | perl -n -e'/: (ami-.+)$/ && print ')

# create the 'ami.tf' file from the template:
export AMI_GENERATED_BY_PACKER="$ami" && envsubst < ami.tf.template > ami.tf

как только скрипт сделан, он создал ami.tf файл, который может выглядеть так:

# "ami.tf" was automatically generated from the template "ami.tf.template".
variable "ami" {
  default     = "ami-aa92a441"
  description = "The latest AMI."
}

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

resource "aws_launch_configuration" "foo" {
  image_id = "${var.ami}"
  ...
}