簡體   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