TerraformでAmazon ECSをデプロイする時のALBターゲットグループ関連付けエラーを解消してみた
TerraformでAmazon ECSがデプロイできない
おのやんです。
TerraformでAmazon ECS(以下、ECS)のサービスをデプロイしようとした時に、ALBとターゲットグループの関連付けが原因でデプロイできないことがあります。
terraform plan
コマンドでTerraformコードのエラーの多くを検知できますが、今回はterraform plan
で検知できるものではありませんでした。また、Application Load Balancer(以下、ALB)とターゲットグループの関連付けはエラーとは直接関係なかったので、解決までにしばらく時間がかかりました。
ということで、「こういう場合でもterraform apply
のエラーになるよ〜」という共有の気持ちで、今回紹介します
エラー内容
ALBとECSをTerraformで記述している状態で、terraform apply
を実行すると、以下のエラーが出ました
% terraform apply
...
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m20s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m30s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m40s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m50s elapsed]
Error: creating ECS Service (aws-test-ecs-service-web): InvalidParameterException: The target group with targetGroupArn arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXX:targetgroup/aws-test-tg-web/XXXXXXXX does not have an associated load balancer.
│
│ with module.ecs.aws_ecs_service.ecs_service_web,
│ on ../modules/ecs/main.tf line 208, in resource "aws_ecs_service" "ecs_service_web":
│ 208: resource "aws_ecs_service" "ecs_service_web" {
The target group with targetGroupArn arn:aws... does not have an associated load balancer.
とあるので、ALBとターゲットグループを関連づけていないことが原因と書いてあるのですが、私の場合はECSでもALBでもALB・ターゲットグループの関連付けは設定していました。
resource "aws_ecs_service" "aws_test_ecs_service_web" {
name = "aws-test-ecs-service-web"
cluster = aws_ecs_cluster.ecs_cluster.arn
launch_type = "FARGATE"
task_definition = aws_ecs_task_definition.ecs_task_definition_web.arn
desired_count = 1
platform_version = "1.4.0"
network_configuration {
assign_public_ip = false
security_groups = [module.sg_ecs.security_group_id]
subnets = var.private_subnets
}
load_balancer {
target_group_arn = var.alb_tg_web_arn
container_name = "nginx"
container_port = 80
}
}
resource "aws_lb" "aws_test_alb" {
name = "aws-test-alb"
internal = false
load_balancer_type = "application"
}
resource "aws_lb_listener" "aws_test_listener_public_http" {
load_balancer_arn = aws_lb.public.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
target_group_arn = aws_lb_target_group.aws_test_tg.arn
}
}
resource "aws_lb_target_group" "aws_test_tg" {
name = "aws-test-tg"
vpc_id = var.vpc_id
target_type = "ip"
port = 80
protocol = "HTTP"
deregistration_delay = 300
health_check {
path = "/"
matcher = "200-399"
timeout = "25"
}
}
エラー原因・解消
上記のコードを見て気づく方もいると思いますが、今回のエラーはALBのデフォルトアクションがredirect
の設定になっていることが原因です。なので、Terraformコードの下記の部分をforward
の設定に変えると、正常にデプロイすることができました。
resource "aws_lb_listener" "aws_test_listener_public_http" {
load_balancer_arn = aws_lb.public.arn
port = 80
protocol = "HTTP"
default_action {
- type = "redirect"
- redirect {
- port = "443"
- protocol = "HTTPS"
- status_code = "HTTP_301"
- }
+ type = "forward"
target_group_arn = aws_lb_target_group.aws_test_tg.arn
}
}
そもそも、target_group_arn
はredirect
の設定では使用しませんので、ALBの設定自体が間違えていたことになります。リダイレクトの場合、クライアントからの通信は指定された新しいURLに直接リダイレクトされるため、ターゲットグループは関係ありません。
target_group_arn - (Optional) ARN of the Target Group to which to route traffic. Specify only if type is forward and you want to route to a single target group. To route to one or more target groups, use a forward block instead. Cannot be specified with forward.
例えば、クライアントからのアクセスをHTTPSにリダイレクトした後にターゲットグループに転送するには、2つのリスナーを設定する必要があります。1つ目のリスナーでHTTPからHTTPSにリダイレクト、もう1つのHTTPSリスナーでターゲットグループにトラフィックを転送します。
#------------------------------------------------------------------------------#
# HTTPSへリダイレクト
#------------------------------------------------------------------------------#
resource "aws_lb_listener" "aws_test_listener_public_http" {
load_balancer_arn = aws_lb.public.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
#------------------------------------------------------------------------------#
# ターゲットグループへ転送
#------------------------------------------------------------------------------#
resource "aws_lb_listener" "aws_test_listener_public_https" {
load_balancer_arn = aws_lb.public.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = "arn:aws:acm:ap-northeast-1:<account-id>:certificate/<certificate-id>"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.aws_test_tg.arn
}
}
ドキュメントを読もう
今回のエラーは、ドキュメントをよく読んでいれば避けられるものでした。TerraformのLinterに頼るのもいいですが、コードの実装の際には公式のドキュメントを参照するようにしましょう。デプロイ時の不要なエラーを回避できるかもしれません。では!