【问题标题】:Terraform: how to attach volumes from previous EC2 instance?Terraform:如何从以前的 EC2 实例附加卷?
【发布时间】:2018-08-29 19:26:13
【问题描述】:

我有一个 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。

提前致谢!

【问题讨论】:

    标签: terraform


    【解决方案1】:

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

    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 将附加卷或更新状态(如果已附加)。

    【讨论】:

    • 对于其他阅读本文的人,尽管 OP 未列出,但上述代码不会在特定挂载点显示添加的设备。这需要单独完成。
    【解决方案2】:
    1. 使用单独的资源创建 EBS 卷:aws_ebs_volume
    2. 将实例配置为在引导期间附加卷。例如,您可以有一个使用 AWS CLI 的 attach-volume 命令的 User Data 脚本。
    3. 如果实例崩溃,或者如果您想替换它以部署新代码,则运行 terraform apply,替换实例将启动并重新附加相同的 EBS 卷。

    如果您希望 Instance 能够自动恢复,那就更棘手了。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      • 1970-01-01
      • 2015-04-10
      • 2014-11-05
      • 2017-12-05
      相关资源
      最近更新 更多