You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何每次执行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(强制替换),这是核心原因:

  1. 首次创建Fargate服务时,AWS会自动为服务添加默认的capacity_provider_strategy配置(使用FARGATE容量提供商,weight=100,base=1)。
  2. 你的Terraform代码中没有显式定义这个块,Terraform会将AWS自动生成的配置记录到状态文件中。
  3. 再次执行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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:14:57