bash 如何将打包器输出 ami id 自动链接到 terraform 变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37357618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I chain packer output ami id to terraform variables automatically?
提问by fips
I'm using packer with ansible provisioner to build an ami, and terraform to setup the infrastructure with that ami as a source - somewhat similar to this article: http://www.paulstack.co.uk/blog/2016/01/02/building-an-elasticsearch-cluster-in-aws-with-packer-and-terraform
我正在使用带有 ansible 配置器的打包器来构建一个 ami,并使用 terraform 以该 ami 作为源来设置基础设施 - 有点类似于这篇文章:http: //www.paulstack.co.uk/blog/2016/01/ 02/building-an-elasticsearch-cluster-in-aws-with-packer-and-terraform
When command packer build pack.json
completes successfully I get the output ami id in this format:
当命令packer build pack.json
成功完成时,我得到以下格式的输出 ami id:
eu-central-1: ami-12345678
In my terraform variables variables.tf
I need to specify the source ami id, region etc. The problem here is that I don't want to specify them manually or multiple times. For region (that I know beforehand) it's easy since I can use environment variables in both situations, but what about the output ami? Is there a built-in way to chain these products or some not so hacky approach to do it?
在我的 terraform 变量中,variables.tf
我需要指定源 ami id、区域等。这里的问题是我不想手动或多次指定它们。对于区域(我事先知道),这很容易,因为我可以在两种情况下使用环境变量,但是输出 ami 呢?是否有一种内置的方式来链接这些产品,或者一些不那么黑客的方法来做到这一点?
EDIT:Hacky approach for anyone who might be interested. In this solution I'm grep
ing the aws region & ami from packer output and use a regular expression in perl to write the result into a terraform.tfvars
file:
编辑:对于任何可能感兴趣的人来说,Hacky 方法。在此解决方案中,我grep
从打包程序输出中输入 aws 区域和 ami,并在 perl 中使用正则表达式将结果写入terraform.tfvars
文件:
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}
回答by dayer4b
You should consider using Terraform's Data Sourcefor aws_ami
. With this, you can rely on custom tags that you set on the AMI when it is created (for example a version number or timestamp). Then, in the Terraform configuration, you can simply filter the available AMIs for this account and region to get the AMI ID that you need.
您应该考虑将 Terraform 的数据源用于aws_ami
. 有了这个,您可以依赖您在创建 AMI 时在 AMI 上设置的自定义标签(例如版本号或时间戳)。然后,在 Terraform 配置中,您可以简单地过滤此账户和区域的可用 AMI 以获取您需要的 AMI ID。
https://www.terraform.io/docs/providers/aws/d/ami.html
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"]
}
NOTE: in the example above (from the docs), the combination of filters is probably excessive. You can probably get by just fine with something like:
注意:在上面的示例中(来自文档),过滤器的组合可能过多。您可能可以通过以下方式过得很好:
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}"
}
An additional benefit of this is that you can deploy to multiple regions with the same configuration and no variable map!
这样做的另一个好处是,您可以使用相同的配置部署到多个区域,无需变量映射!
回答by Martin Atkins
The "official" way that is recommended by Hashicorp is to use their product Atlas as a "middleman" between the two. You'd use the Atlas post-processor in Packerto record the artifacts (AMI ids, in your case) and then use the atlas_artifact
resource in Terraformto read the ids back out again for use in Terraform.
Hashicorp 推荐的“官方”方式是使用他们的产品 Atlas 作为两者之间的“中间人”。您将使用Packer 中的 Atlas 后处理器来记录工件(在您的情况下为 AMI id),然后使用Terraform 中的atlas_artifact
资源再次读取这些 id 以在 Terraform 中使用。
In this case, you would obtain the ids from the resource rather than passing them in using variables.
在这种情况下,您将从资源中获取 id,而不是使用变量传递它们。
Aside from Atlas the other options are rather limited, and in some cases hacky.
除了 Atlas 之外,其他选项都相当有限,在某些情况下也很糟糕。
If you want to do it without any external services at all then you can experiment with the local shell post-processoras a way to run a local command on your artifact, or you can use the machine-readable outputto extract the AMI ids and write them into a variables file for Terraform.
如果你想在没有任何外部服务的情况下完成它,那么你可以尝试使用本地 shell 后处理器作为在你的工件上运行本地命令的一种方式,或者你可以使用机器可读的输出来提取 AMI id 和将它们写入 Terraform 的变量文件中。
A further option is to write your own post-processor plugin that interacts with some software you already use, as an alternative to Atlas. For example, with some of my colleagues I wrote a post-processor to record artifacts as metadata in Buildkite, which we then subsequently retrieve using the Buildkite API. This requires writing custom code in Go.
另一种选择是编写您自己的后处理器插件,与您已经使用的某些软件进行交互,作为 Atlas 的替代方案。例如,我和我的一些同事一起编写了一个后处理器来将工件记录为 Buildkite 中的元数据,然后我们随后使用Buildkite API进行检索。这需要在 Go 中编写自定义代码。
At the time of writing Terraform version 0.7 is still under development, but it is planned to include a new feature that allows querying the EC2 API for AMIs directly, which will (if it indeed lands for 0.7) allow a further option of tagging the AMI with Packer and then finding it directly from EC2 using those tags. This uses EC2 itself as the "middleman", which is perhaps less awkward since it was involved already as the storage for the AMI anyway.
在撰写本文时,Terraform 0.7 版仍在开发中,但计划包含一项新功能,允许直接查询 AMI 的 EC2 API,这将(如果它确实适用于 0.7)允许进一步选择标记 AMI使用 Packer,然后使用这些标签直接从 EC2 中找到它。这使用 EC2 本身作为“中间人”,这可能不那么尴尬,因为无论如何它已经作为 AMI 的存储参与了。
回答by Philipp Cla?en
This is the approach that I used:
这是我使用的方法:
- Wrap the packer call and get the AMI by parsing the output
- Use the parsed AMI to create a Terraform files which provides the value as a variable
- 包装packer调用并通过解析输出获取AMI
- 使用解析的 AMI 创建一个 Terraform 文件,该文件将值作为变量提供
It is similar to the version in the edited answer. In more detail, it can look like this:
它类似于编辑后的答案中的版本。更详细地说,它可能如下所示:
First, create a file called ami.tf.template
:
首先,创建一个名为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."
}
This template will be used to create the ami.tf
file, which makes the AMI from packer available to your existing Terraform setup.
此模板将用于创建ami.tf
文件,从而使打包程序中的 AMI 可用于您现有的 Terraform 设置。
Second, create a shell wrapper script for running packer. You can use the following ideas:
其次,创建一个 shell 包装脚本来运行打包程序。您可以使用以下想法:
# 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
Once the script is done, it has created an ami.tf
file, which may look like this:
脚本完成后,它会创建一个ami.tf
文件,它可能如下所示:
# "ami.tf" was automatically generated from the template "ami.tf.template".
variable "ami" {
default = "ami-aa92a441"
description = "The latest AMI."
}
Finally, put that file next to your existing Terraform setup. Then you can then access the AMI like this:
最后,将该文件放在您现有的 Terraform 设置旁边。然后,您可以像这样访问 AMI:
resource "aws_launch_configuration" "foo" {
image_id = "${var.ami}"
...
}