Terraform(AWS)でよく発生しているエラーとその対処法(ALB編)

2023/07/11に公開

概要

初めまして、Fujiyaと申します。
普段はAWSのインフラを主にTerraformを用いて構築等を行なっております。
そこで、Terraformを用いてAWS(Amazon Web Servise)のインフラを自身が構築する際によく発生するエラーとその対処法についてまとめたいと思います。
まず初めにApplication Load Balancer(ALB)にて発生するエラーについて紹介いたします。
※最新のバージョンでは解決されている可能性があります。

その1 ALBのターゲットの内容変更 (DuplicateTargetGroupName Error)

一つ目はALB(Application Load Balancer)のターゲットの内容変更などの際に発生する以下のようなエラーである。

Error: error creating LB Target Group: DuplicateTargetGroupName: A target group with the same name 'my-target-group' exists, but with different settings
│ 	status code: 400, request id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx

発生時の状況

このエラーはTerraformでターゲットグループの内容(例えばターゲットのポート)を変更した際走る処理が、修正ではなく作成の処理であるから発生するエラーである。

例を挙げて説明をすると、例えば上記のようにmy-target-groupがあったとする。そのターゲットグループのポートを80から443に変更したいとする。当然であるがこちら側の認識としてはターゲットグループを作り替えるのではなくターゲットグループの中身のみを修正したいと思っており、以下のようにterrform planを実行した際も変更として反映されているかのようにさも見える。

# module.alb.aws_lb_target_group.my_ecs must be replaced
+/- resource "aws_lb_target_group" "my_ecs" {
      ~ arn                                = "arn:aws:elasticloadbalancing:xx-xx-x:0123456789012:targetgroup/my-target-group/xxxxxxxxxxxxxxxx" -> (known after apply)
      ~ arn_suffix                         = "targetgroup/my-target-group/xxxxxxxxxxxxxxxx" -> (known after apply)
      ~ id                                 = "arn:aws:elasticloadbalancing:xx-xx-x:0123456789012:targetgroup/my-target-group/xxxxxxxxxxxxxxxx" -> (known after apply)
      ~ load_balancing_algorithm_type      = "round_robin" -> (known after apply)
        name                               = "my-target-group"
      ~ port                               = 80 -> 443 # forces replacement
      + preserve_client_ip                 = (known after apply)
      ~ protocol_version                   = "HTTP1" -> (known after apply)
      - tags                               = {} -> null
      ~ tags_all                           = {} -> (known after apply)
        # (8 unchanged attributes hidden)


      ~ stickiness {
          ~ cookie_duration = 300 -> (known after apply)
          + cookie_name     = (known after apply)
          ~ enabled         = false -> (known after apply)
          ~ type            = "lb_cookie" -> (known after apply)
        }
        # (1 unchanged block hidden)
    }

実際の挙動とその原因

しかしながら、実際の挙動としては新しく443のポートを指定したターゲットグループを登録し、80ポートのターゲットグループを削除するという形の処理が走ることとなる。そのため、同名のターゲットグループが違う内容で生成されることとなり、初めのエラーが表示されることとなる。
この原因として挙げられるのはAWSそのものの仕様である。AWSでは一度作成したターゲットグループの基本設定(ターゲットの種類、所属するVPC、通信プロトコル、ポートなど)は後から変更することができない。そのため新規で基本的には作り直す必要がある。そのため、先に説明したように新しいものを作成し、古いものを削除するという形がTerraformのApply実行の際に取られている。
また、ターゲットグループは必ず一意な名前でなければならないという制約があるため同名のターゲットグループは作成および存在することができない。
結果として同名のターゲットを作成する形になってしまいエラーが出るというのが原因である。

エラーの解消方法

このエラーの解消方法としては二つ存在する。
一つ目は既存のターゲットグループを削除する。AWS上に存在する既存のターゲットグループを削除し、再度Terraform Applyを行いターゲットグループを構築する。
この場合、一時的とはいえターゲットグループを削除するためALBからECSもしくはEC2などへのアクセスは出来なくなりダウンタイムが発生してしまう。もし、ダウンタイムが発生しても問題ない場合はこちらでの解決を行うのが一番手っ取り早く簡単な方法である。

二つ目は、ターゲットグループの名前を変更する。
結論にあるようにこのエラーの根本的な原因は名前の重複によるものである。そのため名前を重複させなければ良いだけの話である。つまり、リリース前に変更するターゲットグループの名称を変更しさえすればそもそもこのエラーに出会うことはなくなる。
しかしながら、毎回修正のたびに名称を変更することは面倒であるし、忘れる可能性もある。そこで、Terraformにはname_prefixという機能がある。これはApply時にランダムな文字列を追加し、名前が一意になるように作成してくれるため毎回修正する必要がなくなる。ただし、このname_prefixにも弱点があり、特定も文字数以上の場合は使用することができなくなる。そのため長い名前のターゲットグループなどを作成している場合はこのname_prefixに相当するような機能の実装を個人で行う必要がある。

その2 ECSにおけるALBに所属しないターゲットグループの選択(The target group with targetGroupArn XXX does not have an associated load balancer.)

二つ目はAmazon ECS(Amazon Elastic Container Service)のALBに紐付けを行う際に以下のようなエラーが発生することがある。

╷
│ Error: error updating ECS Service (arn:aws:ecs:us-east-1:************:service/my-ecs-cluster/my-ecs-service): InvalidParameterException: The target group with targetGroupArn arn:aws:elasticloadbalancing:us-east-1:************:targetgroup/my-target-group/XXXXXXXXXXXXXXXX does not have an associated load balancer.
│ 
╵

発生時の状況

このエラーはTerraformですでにインフラを構築されており、そのインフラ内に新たにECSを実装する場合などに発生することがある。

例を挙げて説明すると、既にECS上でmy-ecs-aというサービスが動いていたとする。このサービスを何らかの影響でリプレイスなどが必要となりmy-ecs-bというサービスを稼働させた、リリース後何らかの障害などで切り戻し作業が発生した時用に既存のECSを起動した状態で残しておいたとする。(Terraformの修正はなし)
その後、急ぎでリリースを行いたい内容が発生し、リリースのためterraform planを実行すると該当箇所は以下のように表示され、問題ないと思われる。

# module.ecs.aws_ecs_service.my_ecs will be updated in-place
  ~ resource "aws_ecs_service" "my_ecs" {
        id                                 = "arn:aws:ecs:us-east-1:************:service/my-ecs-cluster/my-ecs-service"
        name                               = "my-ecs-service"
        tags                               = {}
      ~ task_definition                    = "my-task-definition:XX" -> (known after apply)
        # (14 unchanged attributes hidden)

実際の挙動とその原因

しかしながら、実際はterraform applyを行うと該当のECSのコンテナを新しく起動する際にターゲットグループがALBに紐付いていないためにErrorが発生してしまう。
この原因としては、先ほどからも記述しているようにALBがない状態でターゲットグループにECSをアタッチしようとしたことが起因して発生している。
実際にAmazon ECSのドキュメント内に以下のような記述がある。

The Amazon ECS service requires an explicit dependency on the Application Load Balancer listener rule and the Application Load Balancer listener. This prevents the service from starting before the listener is ready.
参照: https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#aws-resource-ecs-service--examples

エラーの解消方法

エラーの解消方法としては二つある。
一つ目はALBのリスナールールに該当のターゲットグループを登録する。今回のエラーの根本の原因はALBにターゲットグループが紐付いていないことであり、これを紐付けることによって解消することは明白である。したがって、影響のないパスに該当のターゲットグループを振り分ける修正をTerraform上で実行すれば解消される。(コンソール上で行うとALBをTerraformで管理している場合、編集が破棄されるため、Terraform側で修正が必要となる。)

二つ目としては、ECSとターゲットグループの紐付けを解除することでこのエラーが解消される。
このエラーの原因としてはALBに紐付く前のターゲットグループへECSをアタッチした際に発生するため、その紐付けそのものを行わなければ発生しない。そのため以下のようなALBの紐付けを行なっている行をコメントアウトすることによってエラーは解消される。

  health_check_grace_period_seconds = 3600
  
  load_balancer {
    target_group_arn = var.alb_my_target_group_arn
    container_name   = "my_container"
    container_port   = var.ecs_container_port
  }

  depends_on = [
    var.alb_listener_my_ecs
  ]

まとめ

自身がこれまでTerraformを用いてAWSのインフラを構築してきた際にALB関連でよく発生したエラーに関してその発生原因と対処法など紹介させていただきました。なかなか初めて遭遇すると対処法が分からなかったり、terraform planでは発見できにくいようなエラーでしたので、どなたかが同じような状況になった時の一助にでもなれば幸いです。
もし、ご意見やもっと良い方法などがございましたらご気軽にコメントなどをお願いいたします。
ご精読ありがとうございました。

Discussion