为何每次执行terraform apply都会重建AWS ECS Service?
ECS Fargate服务重复销毁重建的原因及解决办法
问题场景
使用Terraform部署AWS ECS Fargate类型的openldap服务,首次执行terraform apply后资源正常运行,但再次执行该命令时,Terraform会销毁现有ECS服务及关联任务,重新创建新的服务实例。
相关Terraform配置
resource "aws_ecs_service" "openldap" { name = "openldap" cluster = aws_ecs_cluster.ecs_cluster_ldap.id task_definition = aws_ecs_task_definition.openldap.arn desired_count = 1 network_configuration { subnets = [aws_subnet.sn-public-access.id] security_groups = [aws_security_group.secgrp-public-access.id] assign_public_ip = true } } resource "aws_ecs_task_definition" "openldap" { family = "openldap-task-definition" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 execution_role_arn = aws_iam_role.ecs_task_execution_role.arn container_definitions = jsonencode([ { name = "openldap" image = "public.ecr.aws/bitnami/openldap:2.6.7" cpu = 512 memory = 1024 essential = true portMappings = [ { containerPort = 1389 hostPort = 1389 }, { containerPort = 1636 hostPort = 1636 } ] environment = [ { name = "LDAP_PORT_NUMBER", value = "1389" }, { name = "LDAP_ROOT", value = "dc=example,dc=com"}, { name = "LDAP_ADMIN_USERNAME", value = "admin" }, { name = "LDAP_ADMIN_PASSWORD_FILE", value = "/openldap/ldap_admin_password.txt" }, { name = "LDAP_CUSTOM_LDIF_DIR", value = "/openldap/ldif" }, { name = "BITNAMI_DEBUG", value = "yes" }, { name = "LDAP_TLS_CERT_FILE", value = "/openldap/certs/ldapserver-cert.pem" }, { name = "LDAP_TLS_KEY_FILE", value = "/openldap/certs/ldapserver-key.pem" }, { name = "LDAP_TLS_CA_FILE" , value = "/openldap/certs/ldapserver-cacerts.pem" }, { name = "LDAP_ENABLE_TLS", value = "yes" }, { name = "LDAP_ENABLE_RQUIRE_TLS", value = "no" }, { name = "LDAP_LDAPS_PORT_NUMBER", value = "1636" } ] logConfiguration = { logDriver = "awslogs" options = { awslogs-group = "cwlg-ecs-ldap" awslogs-stream-prefix = "openldap" awslogs-region = "${var.region}" } } mountPoints = [ { "sourceVolume": "openldap", "containerPath": "/openldap" } ] } ]) volume { name = "openldap" efs_volume_configuration { file_system_id = aws_efs_file_system.sandbox-efs.id root_directory = "ldap/" transit_encryption = "ENABLED" transit_encryption_port = 2049 } } runtime_platform { operating_system_family = "LINUX" cpu_architecture = "X86_64" } }
第二次terraform apply的输出
Terraform will perform the following actions: # aws_ecs_service.openldap must be replaced -/+ resource "aws_ecs_service" "openldap" { - health_check_grace_period_seconds = 0 -> null ~ iam_role = "/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS" -> (known after apply) ~ id = "arn:aws:ecs:eu-central-1:xxxxxxxxxxxx:service/ecs_cluster_ldap/openldap" -> (known after apply) + launch_type = (known after apply) name = "openldap" ~ platform_version = "LATEST" -> (known after apply) - propagate_tags = "NONE" -> null - tags = {} -> null ~ triggers = {} -> (known after apply) # (10 unchanged attributes hidden) - capacity_provider_strategy { # forces replacement - base = 1 -> null - capacity_provider = "FARGATE" -> null - weight = 100 -> null } - deployment_circuit_breaker { - enable = false -> null - rollback = false -> null } - deployment_controller { - type = "ECS" -> null } # (1 unchanged block hidden) } Plan: 1 to add, 0 to change, 1 to destroy.
原因分析
从Terraform的执行计划可以看到,capacity_provider_strategy块被标记为forces replacement(强制替换),这是核心原因:
- 首次创建Fargate服务时,AWS会自动为服务添加默认的
capacity_provider_strategy配置(使用FARGATE容量提供商,weight=100,base=1)。 - 你的Terraform代码中没有显式定义这个块,Terraform会将AWS自动生成的配置记录到状态文件中。
- 再次执行
terraform apply时,Terraform对比代码和状态,发现代码里缺少capacity_provider_strategy块,认为需要移除该配置。而该属性属于替换级变更——修改它必须销毁并重建ECS服务,因此触发了服务的重建流程。
解决办法
在aws_ecs_service资源中显式定义capacity_provider_strategy块,匹配AWS默认的配置,让Terraform的代码和状态保持一致:
resource "aws_ecs_service" "openldap" { name = "openldap" cluster = aws_ecs_cluster.ecs_cluster_ldap.id task_definition = aws_ecs_task_definition.openldap.arn desired_count = 1 # 显式添加容量提供商策略,匹配AWS默认配置 capacity_provider_strategy { capacity_provider = "FARGATE" weight = 100 base = 1 } network_configuration { subnets = [aws_subnet.sn-public-access.id] security_groups = [aws_security_group.secgrp-public-access.id] assign_public_ip = true } }
另外,也可以显式指定launch_type = "FARGATE",虽然不是必须,但能让配置更清晰,避免隐式推断可能带来的问题:
resource "aws_ecs_service" "openldap" { name = "openldap" cluster = aws_ecs_cluster.ecs_cluster_ldap.id task_definition = aws_ecs_task_definition.openldap.arn desired_count = 1 launch_type = "FARGATE" # 显式指定启动类型 capacity_provider_strategy { capacity_provider = "FARGATE" weight = 100 base = 1 } network_configuration { subnets = [aws_subnet.sn-public-access.id] security_groups = [aws_security_group.secgrp-public-access.id] assign_public_ip = true } }
修改后执行terraform apply,Terraform会将显式定义的配置同步到状态中,后续再执行terraform apply时,代码和状态完全一致,就不会再触发服务的销毁重建了。
内容的提问来源于stack exchange,提问作者Joerg F.
相关产品推荐
相关产品推荐

