【Terraform】Autoscaling GroupのLaunch Configurationを変更するのに失敗した話

先日、新しいECS ClusterをTerraformで作った。EC2インスタンスは1台のみだが、Launch Configurationを用意してAutoscaling Groupを作成した。

resource "aws_launch_configuration" "ecs_cluster" {
  name                   = "ecs_cluster"
  image_id             = data.aws_ami.aws_optimized_ecs.id
  iam_instance_profile = aws_iam_instance_profile.ecs-cluster.name
  security_groups      = [aws_security_group.ecs-cluster.id]
  user_data            = file("${path.module}/user_data.sh")
  instance_type        = "t3.medium"

  root_block_device {
    delete_on_termination = true
    encrypted             = false
    volume_size           = "30"
    volume_type           = "gp2"
  }
}

しかしその後、key_nameの登録を忘れておりEC2インスタンスssh接続できないことに気づいたため、Launch Configurationを修正した。

 resource "aws_launch_configuration" "ecs_cluster" {
   name                   = "ecs_cluster"
   image_id               = data.aws_ami.aws_optimized_ecs.id
   iam_instance_profile = aws_iam_instance_profile.ecs-cluster.name
   security_groups      = [aws_security_group.ecs-cluster.id]
   user_data            = file("${path.module}/user_data.sh")
   instance_type        = "t3.medium"
+ key_name           = "ecs_cluster"

   root_block_device {
     delete_on_termination = true
     encrypted             = false
     volume_size           = "30"
     volume_type           = "gp2"
   }
 }

ところが、この状態で terraform apply しようとしても失敗してしまった。

Error: error deleting Autoscaling Launch Configuration (terraform-20201203072824459100000004): ResourceInUse: Cannot delete launch configuration terraform-20201203093824531400000001 because it is attached to AutoScalingGroup ecs_cluster

これは、TerraformがLaunch Configurationを一旦削除し、同名のものを新しく作って追加しようとしているため。 terraform plan の結果は Plan: 1 to add, 1 to change, 1 to destroy. となっており、 changeはAutoscaling Groupを、addとdestroyはLaunch Configurationを指している。

これを避けるためには2つの処理が必要となる。まず lifecycle の中で create_before_destroy = true を追加すること。通常であれば、resourceに対するupdateができない場合Terraformは古い方をdestroyしてから新しい方をcreateするが、この指定をすると先に新しいresourceのcreateが行われ、その後古い方をdestroyするようになる。これにより、Autoscaling Groupが起動しているのにLaunch Configurationがなくなってしまうということが起こらない。
もう一つは、 name の指定をやめるか、あるいは name_prefix の指定に変えること。これにより、新旧のLaunch Configurationが異なる名前を持つようになる。この指定を行わないと、同じ名前を持った新旧のresourceが一時的に併存することになってしまい、applyに失敗する可能性がある。

 resource "aws_launch_configuration" "ecs_cluster" {
- name                   = "ecs_cluster"
+ name_prefix            = "ecs_cluster_"   
  image_id             = data.aws_ami.aws_optimized_ecs.id
   iam_instance_profile = aws_iam_instance_profile.ecs-cluster.name
   security_groups      = [aws_security_group.ecs-cluster.id]
   user_data            = file("${path.module}/user_data.sh")
   instance_type        = "t3.medium"
   key_name           = "ecs_cluster"
    
+  lifecycle {
+    create_before_destroy = true
+  }

   root_block_device {
     delete_on_termination = true
     encrypted             = false
     volume_size           = "30"
     volume_type           = "gp2"
   }
 }

このようにすると terraform apply が成功した。