Terraform删除一个EC2实例时为什么会导致所有卷被删除?

70次阅读
没有评论

问题描述

在使用Terraform创建AWS资源时遇到了问题。他在模板中创建了2个EC2实例,每个实例都附加了一个1GB的EBS卷。然而,当他尝试删除其中一个EC2实例时,两个1GB的EBS卷都被销毁了。他确认这两个卷连接到不同的实例上,因此对此情况感到困惑。
以下是他执行的删除命令:

$ terraform destroy -target=aws_instance.jumpserver[1]

这是他的主要Terraform配置文件(main.tf):

# 定义位于公共子网中的web服务器
resource "aws_instance" "jumpserver" {
  count                       = "${var.num_of_instances}"
  ami                         = "${var.ami}"
  instance_type               = "t2.micro"
  key_name                    = "${aws_key_pair.ProdKeypair.id}"
  subnet_id                   = "${aws_subnet.public_subnet.id}"
  vpc_security_group_ids      = ["${aws_security_group.sg_internet_facing.id}"]
  associate_public_ip_address = true
  source_dest_check           = false

  root_block_device = {
    volume_type           = "gp2"
    volume_size           =  "8"
    delete_on_termination = "${var.delete_on_termination}"
  }

  tags = {
    Name = "${format("jump-%01d",count.index+1)}"
  }

  provisioner "remote-exec" {
    inline = ["sudo apt-get  -y install python"]
    connection {
      type        = "ssh"
      user        = "ubuntu"
      private_key = "${file(var.private_key_path)}"
    }
  }
}

# 定义EBS卷
resource "aws_ebs_volume" "vol_generic_data" {
  size              = "1"
  count             = "${var.num_of_instances}"
  type              = "gp2"
  availability_zone = "${element(aws_instance.jumpserver.*.availability_zone, count.index)}"

  tags = {
    Name = "${format("jump-%01d",count.index+1)}"
  }
}

# 将EBS卷附加到EC2实例
resource "aws_volume_attachment" "generic_data_vol_att" {
  device_name = "/dev/xvdf"
  volume_id   = "${element(aws_ebs_volume.vol_generic_data.*.id, count.index)}"
  instance_id = "${element(aws_instance.jumpserver.*.id, count.index)}"
  count       = "${var.num_of_instances}"
}

# 定义位于私有子网中的web服务器
resource "aws_instance" "backendserver" {
  ami                         = "${var.ami}"
  instance_type               = "t2.micro"
  key_name                    = "${aws_key_pair.ProdKeypair.id}"
  subnet_id                   = "${aws_subnet.private_subnet.id}"
  vpc_security_group_ids      = ["${aws_security_group.sg_backend.id}"]
  associate_public_ip_address = false
  source_dest_check           = false
  user_data                   = "${file("install.sh")}"

  tags = {
    Name = "backendserver"
  }
}

解决方案

请注意以下操作可能因版本差异或个人环境不同而有所不同,请在操作前进行充分的备份和测试。

解决方案1:修复EBS卷的可用区问题

问题的根本在于aws_ebs_volume资源的availability_zone属性。该属性取决于aws_instance资源,因此当Terraform销毁EC2实例时,它会认为EBS卷无法独立存在。即使这是一个独立于EC2实例的变量。
为了修复这个问题,您可以将availability_zone属性更改为参考您的VPC的可用区,而不是依赖于EC2实例的可用区。您可以使用类似module.vpc-prod.azs[0]的引用。
下面是您可以进行的更改:

# 定义EBS卷
resource "aws_ebs_volume" "vol_generic_data" {
  size              = "1"
  count             = "${var.num_of_instances}"
  type              = "gp2"
  availability_zone = "us-east-1a"  # 更改为您的VPC的可用区,或使用引用方式

  tags = {
    Name = "${format("jump-%01d",count.index+1)}"
  }
}

解决方案2:使用Terraform生命周期设置

您还可以通过Terraform的生命周期设置来解决这个问题,确保EBS卷在EC2实例销毁之前被销毁。这可以防止Terraform在销毁EC2实例时自动销毁EBS卷。
下面是一个可能的示例配置:

resource "aws_ebs_volume" "vol_generic_data" {
  size              = "1"
  count             = "${var.num_of_instances}"
  type              = "gp2"
  availability_zone = "us-east-1a"  # 更改为您的VPC的可用区,或使用引用方式

  tags = {
    Name = "${format("jump-%01d",count.index+1)}"
  }

  lifecycle {
    prevent_destroy = true  # 防止Terraform销毁EBS卷
  }
}

通过设置prevent_destroy = true,您可以阻止Terraform销毁EBS卷,从而确保在EC2实例销毁之前手动处理EBS卷。

总结

在使用Terraform创建AWS资源时,确保您正确设置EBS卷的可用区,以及根据实际需求使用适当的Terraform生命周期设置,以避免意外的资源销毁。

正文完