Terraform:如何从以前的EC2实例附加卷?

时间:2018-03-20 20:17:51

标签: terraform

我有一个terraform文件,可以创建一个EC2实例和几个卷:

resource "aws_instance" "generic" {
  count                  = "${lookup(var.INSTANCE_COUNT, var.SERVICE)}"
  ami                    = "${var.AMI}"
  instance_type          = "${lookup(var.INSTANCE_TYPE, var.BLD_ENV)}"
  subnet_id              = "${element(var.SUBNET,count.index)}"
  vpc_security_group_ids = ["${var.SECURITY_GROUP}"]
  key_name               = "${var.AWS_KEY_NAME}"
  availability_zone      = "${element(var.AWS_AVAILABILITY_ZONE,count.index)}"
  iam_instance_profile   = "${var.IAM_ROLE}"

  root_block_device {
    volume_type           = "gp2"
    delete_on_termination = "${var.DELETE_ROOT_ON_TERMINATION}"
  }

  ebs_block_device {
    device_name           = "${lookup(var.DEVICE_NAME,"datalake")}"
    volume_type           = "${lookup(var.DATALAKE_VOLUME_TYPE, var.SERVICE)}"
    volume_size           = "${var.NONDATADIR_VOLUME_SIZE}"
    delete_on_termination = "${var.DELETE_ROOT_ON_TERMINATION}"
    encrypted             = true
  }

  ebs_block_device {
    device_name           = "${lookup(var.DEVICE_NAME,"datalake_logdir")}"
    delete_on_termination = "${var.DELETE_ROOT_ON_TERMINATION}"
    volume_type           = "${lookup(var.LOGDIR_VOLUME_TYPE, var.SERVICE)}"
    volume_size           = "${var.NONDATADIR_VOLUME_SIZE}"
    encrypted             = true
  }

  volume_tags {
    Name = "${lookup(var.TAGS, "Name")}-${count.index}"
  }
}

如果ec2实例终止,我如何将现有卷附加到我重新运行terraform时创建的新ec2实例?我希望terraform能以某种方式告诉状态文件实例已经消失,但是卷不是,所以它们应该附加到新创建的EC2上。

提前致谢!

2 个答案:

答案 0 :(得分:2)

首先,将实例,卷和卷附件分开,如下所示:

resource "aws_instance" "generic" {
  ami           = "${var.ami_id}"
  instance_type = "${var.instance_type}"
  count         = "${var.node_count}"
  subnet_id     = "${var.subnet_id}"
  key_name      = "${var.key_pair}"

  root_block_device = {
    volume_type           = "gp2"
    volume_size           = 20
    delete_on_termination = false
  }

  vpc_security_group_ids = ["${var.security_group_ids}"]
}

resource "aws_ebs_volume" "vol_generic_data" {
  size              = 120
  count             = "${var.node_count}"
  type              = "gp2"
}

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.vol_generic_data.*.id, count.index)}"
  count       = "${var.node_count}"
}

然后,如果您的实例被手动终止,则TF应该检测到该实例已消失但仍以TF状态引用,并应尝试重新创建它并附加现有的卷。我还没有尝试过。但是,我已经尝试将现有实例及其卷导入TF状态,因此相同的逻辑应该适用于仅导入卷并将其附加到现有TF管理的实例。您应该可以像这样简单地导入现有卷:

terraform import module.generic.aws_ebs_volume.vol_generic_data vol-0123456789abcdef0

然后TF将附加卷或更新状态(如果已附加)。

答案 1 :(得分:1)

  1. 使用单独的资源创建EBS卷:aws_ebs_volume
  2. 配置实例以在引导期间附加卷。例如,您可以使用User Data脚本,该脚本使用AWS CLI的attach-volume命令。
  3. 如果实例崩溃,或者您想要替换它以部署新代码,则运行terraform apply,替换实例将启动并重新连接相同的EBS卷。
  4. 如果您希望Instance能够自动恢复,则会变得更加棘手。

    • 您可以使用Auto Recovery配置您的实例,但这只能检测实际的VM是否已死;它不会检测在该VM上运行的应用程序是否死亡(例如,崩溃,内存不足)。
    • 更好的方法是使用Auto Scaling Group (ASG)Load Balancer。如果ASG中的任何实例未通过Load Balancer运行状况检查,则会自动替换它们。问题是实例只能在同一可用区(AZ)中附加EBS卷,但ASG可以在任何 AZ中启动实例,因此实例可以在没有任何EBS卷的AZ中启动!解决此问题,尤其是以支持零停机时间部署的方式解决此问题,通常需要超出Terraform。例如,Gruntwork IaC Library中的Auto Scaling Group模块使用多个ASG和通过external data source激活的Python脚本实现此功能。