使用 Terraform,如何回收根 EC2 实例卷?

Reu*_*ery 2 amazon-web-services terraform

我想知道是否有人已经解决了使 EC2 根卷持久化的问题,这样可能会污染实例资源并重新应用,并且实例将使用该卷而不是 ami 的卷?

我从文档中了解到 aws_ebs_volume 和 aws_ebs_volume_attachment 仅适用于非根卷。

Mar*_*ins 5

Terraform 的aws_instance资源需要 AMI,而根设备始终是从该 AMI 的底层 EBS 快照生成的新卷。这是(据我所知)底层 EC2 API 的限制。

如您所见,可以使用将现有 EBS 卷附加到正在运行的实例,aws_ebs_volume_attachment但无法将现有 EBS 卷用作新实例的根文件系统。

关于根卷的官方文档指出,我们在这里最接近您想要的内容是:

  • 关闭旧实例,同时保留其根 EBS 卷。
  • 创建旧根 EBS 卷的快照。
  • 使用创建的快照创建新的 AMI。
  • 使用该新 AMI 启动新映像。

这种多步骤的过程很难单独使用 Terraform 进行编排,因为 Terraform 无法跟踪它在这样一个过程中的位置。但是,当您需要替换实例时,类似以下的配置将允许您通过一些手动工作流程来实现它:

variable "source_volume_id" {
}

resource "aws_ebs_snapshot" "new" {
  volume_id = "${var.source_volume_id}"
}

resource "aws_ami" "new" {
  name = "from-${aws_ebs_snapshot.new.id}"
  virtualization_type = "hvm"
  root_device_name = "/dev/xvda"

  ebs_block_device {
    device_name = "/dev/xvda"
    snapshot_id = "${aws_ebs_snapshot.new.id}"
    volume_size = "${aws_ebs_snapshot.new_volume_size}"
  }
}

resource "aws_instance" "new" {
  ami = "${aws_ami.new.id}"
  # ...etc...
}
Run Code Online (Sandbox Code Playgroud)

此配置假定您已经手动终止了旧的 EC2 实例并记下其根卷 EBS 卷 ID。然后您通过source_volume_id变量传递该卷 ID,它将执行剩余的步骤。

每次source_volume_id更改 Terraform 都应重复此过程,创建新的快照、AMI 和实例。如果您source_volume_id使用最近使用的相同内容再次运行 Terraform ,它应该保持一切不变。

这个半手动过程的一个奇怪的问题是它有一个先有鸡还是先有蛋的问题,在第一次运行时,你可能还没有一个基于你的 AMI 的卷。在这种情况下,您必须首先注释掉除aws_instance资源之外的所有内容,硬编码一个 AMI id 以进行引导,然后让 Terraform 创建该初始实例。在后续运行中,您可以按照上述过程进行操作。

如上所述,Terraform 目前不太适合此类问题。鉴于无论如何都有一些手动步骤,使用更命令性的方法编写整个过程的脚本可能会更简单,例如使用带有您最喜欢的编程语言的 AWS 开发工具包之一,尽管使用 Terraform 作为过程的一部分至少可以让您解脱从跟踪以前使用的快照和 AMI id 以确保它们得到清理的任务。