Как я могу автоматически выводить 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 подход для всех, кто может быть заинтересован. В этом решении я grep
ing регион 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.
это подход, который я использую:
- оберните вызов упаковщика и получите AMI, проанализировав вывод
- используйте проанализированный 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}"
...
}