简体   繁体   English

我如何自动将 output ami id 链接到 terraform 变量?

[英]How can I chain packer output ami id to terraform variables automatically?

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成功完成时,我以这种格式获得 output 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.在我的 terraform 变量variables.tf中,我需要指定源 ami id、区域等。这里的问题是我不想手动或多次指定它们。 For region (that I know beforehand) it's easy since I can use environment variables in both situations, but what about the output ami?对于区域(我事先知道)这很容易,因为我可以在两种情况下使用环境变量,但是 output ami 呢? Is there a built-in way to chain these products or some not so hacky approach to do it?是否有一种内置的方法来链接这些产品或一些不那么 hacky 的方法来做到这一点?

EDIT: Hacky approach for anyone who might be interested.编辑:适用于任何可能感兴趣的人的 Hacky 方法。 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:在这个解决方案中,我grep从打包机 output 获取 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}

You should consider using Terraform's Data Source for aws_ami . 你应该考虑使用Terraform的数据源来实现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). 这样,您可以依赖在创建AMI时在AMI上设置的自定义标记(例如版本号或时间戳)。 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配置中,您只需过滤此帐户和区域的可用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! 这样做的另一个好处是,您可以部署到具有相同配置且没有变量映射的多个区域!

The "official" way that is recommended by Hashicorp is to use their product Atlas as a "middleman" between the two. Hashicorp推荐的“官方”方式是将他们的产品Atlas用作两者之间的“中间人”。 You'd use the Atlas post-processor in Packer to record the artifacts (AMI ids, in your case) and then use the atlas_artifact resource in Terraform to read the ids back out again for use in Terraform. 您将在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之外,其他选择相当有限,在某些情况下是hacky。

If you want to do it without any external services at all then you can experiment with the local shell post-processor as a way to run a local command on your artifact, or you can use the machine-readable output to 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. 另一个选择是编写自己的后处理器插件,与您已经使用的某些软件交互,作为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 . 例如,我和一些同事编写了一个后处理器,用于将工件记录为Buildkite中的元数据 ,然后我们使用Buildkite API进行检索。 This requires writing custom code in Go. 这需要在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. 在撰写本文时,Terraform 0.7版仍处于开发阶段,但计划包含一项新功能,允许直接查询AMI的EC2 API,如果它确实为0.7,则允许进一步选择标记AMI使用Packer,然后使用这些标签直接从EC2中找到它。 This uses EC2 itself as the "middleman", which is perhaps less awkward since it was involved already as the storage for the AMI anyway. 这使用EC2本身作为“中间人”,这可能不那么尴尬,因为它已经作为AMI的存储而已经涉及。

This is the approach that I used: 这是我使用的方法:

  1. Wrap the packer call and get the AMI by parsing the output 通过解析输出来包装打包器并获取AMI
  2. Use the parsed AMI to create a Terraform files which provides the value as a variable 使用解析的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.tf器中的AMI可用于现有的Terraform设置。

Second, create a shell wrapper script for running packer. 其次,创建一个用于运行打包程序的shell包装器脚本。 You can use the following ideas: 您可以使用以下想法:

# 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 $1')

# 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. 最后,将该文件放在现有Terraform设置旁边。 Then you can then access the AMI like this: 然后,您可以像这样访问AMI:

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

I used the simplest approach, I gave my AMI a name, and looked up for the name in Terraform. image.pkr.hcl file -我使用了最简单的方法,我给了我的 AMI 一个名字,然后在image.pkr.hcl文件中查找这个名字——

packer {
  required_plugins {
    amazon = {
      version = ">= 0.0.2"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

source "amazon-ebs" "ubuntu" {
  ami_name      = "your_ami_name"
  instance_type = "t2.micro"
  region        = "${var.aws_region}"
  source_ami_filter {
    filters = {
      name                = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
      root-device-type    = "ebs"
      virtualization-type = "hvm"
    }
    most_recent = true
    owners      = "${var.image_owners}"
  }
  ssh_username = "ubuntu"
}

build {
  name = "build-image"
  sources = [
    "source.amazon-ebs.ubuntu"
  ] 
#.....
}

and ec2.tf file is - ec2.tf文件是 -

data "aws_ami" "ami" {
  most_recent = true
  owners = ["self"]
  filter {
    name = "name"
    values = ["your_ami_name"]
  }
}

output "ami_id" {
  value = data.aws_ami.ami.id
}

resource "aws_instance" "myEc2" {
  ami = data.aws_ami.ami.id
  instance_type = "t2.micro"
  key_name      = "----key"
  vpc_security_group_ids = [
    "launch-wizard-18"
  ]
    user_data = <<-EOL
      #!/bin/bash -xe
      echo "if done file exists it went ok"
      touch done.txt

      EOL

  tags = {
    Name = "child-of-your-ami"
  }
}

Hope this helps希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在packer ami数据源中添加区域 - How to add region in packer ami data source 如果我更改 AMI ID,Terraform 不会创建新的 ec2 实例 - Terraform does not create a new ec2 instance if I change the AMI ID 如何使用 Terraform 的模块 output 作为另一个 Terraform 模块的输入? - How can I use a Terraform's modules output as an input to another Terraform module? 打包程序无法找到私有 AMI - packer not able to find private AMI 如何在 Terraform 中自动添加 kube.netes 客户端密码作为文件挂载? - How can I automatically add a kubernetes client secret as a file mount in Terraform? 自定义私有 AWS AMI 能否用作创建新打包程序映像的基础 - Can a custom private AWS AMI be used as a base for creating a new packer image 调用数据/资源时如何使用terraform模块中的变量? - How can I use variables in terraform module when call data/resources? Terraform - 如何将列表转换为 map(如何使用 terraform 获取 AMI 标签) - Terraform - How to convert lists into map (How to fetch AMI tags using terraform) 如何将 Terraform 中的逻辑用于 Azure? - How can i use logic in Terraform for Azure? 打包程序“source_ami_filter”中的“所有者”字段有何作用? - what does "Owner" field in packer "source_ami_filter" work on?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM