繁体   English   中英

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

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

我正在使用加壳器和 ansible 供应商来构建一个 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成功完成时,我以这种格式获得 output ami id:

eu-central-1: ami-12345678

在我的 terraform 变量variables.tf中,我需要指定源 ami id、区域等。这里的问题是我不想手动或多次指定它们。 对于区域(我事先知道)这很容易,因为我可以在两种情况下使用环境变量,但是 output ami 呢? 是否有一种内置的方法来链接这些产品或一些不那么 hacky 的方法来做到这一点?

编辑:适用于任何可能感兴趣的人的 Hacky 方法。 在这个解决方案中,我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}

你应该考虑使用Terraform的数据源来实现aws_ami 这样,您可以依赖在创建AMI时在AMI上设置的自定义标记(例如版本号或时间戳)。 然后,在Terraform配置中,您只需过滤此帐户和区域的可用AMI即可获取所需的AMI ID。

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中使用Atlas后处理器来记录工件(在您的情况下为AMI ID),然后使用Terraform中的atlas_artifact资源再次读取ID以便在Terraform中使用。

在这种情况下,您将从资源获取ID,而不是使用变量传递它们。

除了Atlas之外,其他选择相当有限,在某些情况下是hacky。

如果你想在没有任何外部服务的情况下完成它,那么你可以尝试使用本地shell后处理器作为在工件上运行本地命令的方法,或者你可以使用机器可读输出来提取AMI ID和将它们写入Terraform的变量文件中。

另一个选择是编写自己的后处理器插件,与您已经使用的某些软件交互,作为Atlas的替代品。 例如,我和一些同事编写了一个后处理器,用于将工件记录为Buildkite中的元数据 ,然后我们使用Buildkite API进行检索。 这需要在Go中编写自定义代码。

在撰写本文时,Terraform 0.7版仍处于开发阶段,但计划包含一项新功能,允许直接查询AMI的EC2 API,如果它确实为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.tf文件,这使得ami.tf器中的AMI可用于现有的Terraform设置。

其次,创建一个用于运行打包程序的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 $1')

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

我使用了最简单的方法,我给了我的 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"
  ] 
#.....
}

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

希望这可以帮助

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM