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

Terraform创建ECS架构问题:Capacity Provider未关联集群及脚本修正

ECS实例无法连接集群的Terraform脚本修正

你遇到的ECS实例无法连接集群的核心原因是Capacity Provider未与ECS集群绑定,同时脚本缺失ECS实例必需的安全组出站规则(实例需要出站流量与ECS控制平面通信、拉取镜像)。以下是具体修正方案:

核心修正点

1. 关联Capacity Provider与ECS集群

修改aws_ecs_cluster资源,添加capacity_providers和default_capacity_provider_strategy配置,将创建的Capacity Provider绑定到集群:

resource "aws_ecs_cluster" "my_cluster" {
  name = "ecs-demo"

  # 关联Capacity Provider
  capacity_providers = [aws_ecs_capacity_provider.my_capacity_provider.name]
  default_capacity_provider_strategy {
    capacity_provider = aws_ecs_capacity_provider.my_capacity_provider.name
    weight            = 1
    base              = 1
  }
}

2. 补全安全组出站规则

给aws_security_group添加全量出站规则,确保ECS实例能正常与AWS服务通信:

resource "aws_security_group" "my_security_group" {
  name        = "ecs-demo-security-group"
  description = "Allow SSH, HTTP traffic and ECS required outbound"
  vpc_id      = "vpc-xxxx" # 替换为你的VPC ID

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 3000
    to_port     = 3000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 添加ECS实例必需的出站规则
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

3. 修正资源创建顺序

由于ECS集群依赖Capacity Provider,需要添加depends_on确保Terraform创建顺序正确:

resource "aws_ecs_cluster" "my_cluster" {
  name = "ecs-demo"

  capacity_providers = [aws_ecs_capacity_provider.my_capacity_provider.name]
  default_capacity_provider_strategy {
    capacity_provider = aws_ecs_capacity_provider.my_capacity_provider.name
    weight            = 1
    base              = 1
  }

  # 确保集群在Capacity Provider创建后再创建
  depends_on = [aws_ecs_capacity_provider.my_capacity_provider]
}

完整修正后的Terraform脚本

provider "aws" {
  region = "ap-south-1"
}
resource "aws_key_pair" "my_key_pair" {
  key_name   = "any"
  public_key = file("~/.ssh/any.pub")
}
resource "aws_security_group" "my_security_group" {
  name        = "ecs-demo-security-group"
  description = "Allow SSH, HTTP traffic and ECS required outbound"
  vpc_id      = "vpc-xxxx" # 替换为你的VPC ID

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port   = 3000
    to_port     = 3000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 添加ECS实例必需的出站规则
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_ecs_cluster" "my_cluster" {
  name = "ecs-demo"

  # 关联Capacity Provider
  capacity_providers = [aws_ecs_capacity_provider.my_capacity_provider.name]
  default_capacity_provider_strategy {
    capacity_provider = aws_ecs_capacity_provider.my_capacity_provider.name
    weight            = 1
    base              = 1
  }

  # 确保集群在Capacity Provider创建后再创建
  depends_on = [aws_ecs_capacity_provider.my_capacity_provider]
}
resource "aws_iam_role" "my_execution_role" {
  name = "ecs-demo-execution-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })
}
resource "aws_iam_role_policy_attachment" "ecs_execution_role_attachment" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
  role       = aws_iam_role.my_execution_role.name
}

resource "aws_iam_role" "ecs_instance_role" {
  name = "ecs-instance-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}
resource "aws_iam_role_policy_attachment" "ecs_instance_role_attachment" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
  role       = aws_iam_role.ecs_instance_role.name
}
resource "aws_iam_instance_profile" "ecs_instance_profile" {
  name = "ecs-instance-profile"
  role = aws_iam_role.ecs_instance_role.name
}
resource "aws_ecs_capacity_provider" "my_capacity_provider" {
  name = "my-ecs-demo-capacity-provider"
  
  auto_scaling_group_provider {
    auto_scaling_group_arn = aws_autoscaling_group.my_autoscaling_group.arn
    managed_scaling {
      status                    = "ENABLED"
      target_capacity           = 100
    }
    managed_termination_protection = "DISABLED" # 可选,根据需要调整
  }
  tags = {
    Name = "ecs-demo"
  }
}
resource "aws_launch_template" "my_launch_template" {
  name = "ecs-demo-launch-template"
  image_id = "ami-076bbae7511f2cc74" # 确认该AMI是对应区域的ECS优化AMI
  block_device_mappings {
    device_name = "/dev/xvda"
    ebs {
      volume_size = 30
      volume_type = "gp2"
    }
  }
  key_name = aws_key_pair.my_key_pair.key_name
  instance_type = "t2.micro"
  iam_instance_profile {
    name = aws_iam_instance_profile.ecs_instance_profile.name
  }
  network_interfaces {
    security_groups=[aws_security_group.my_security_group.id]  
  }
  user_data = base64encode(<<-EOF
              #!/bin/bash
              echo ECS_CLUSTER=${aws_ecs_cluster.my_cluster.name} >> /etc/ecs/ecs.config
              echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config
              EOF
  )

  tag_specifications {
    resource_type = "instance"

    tags = {
      Name = "ecs-demo"
    }
  }

  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_autoscaling_group" "my_autoscaling_group" {
  desired_capacity     = 1
  max_size             = 2
  min_size             = 1

  
  mixed_instances_policy {
    launch_template {
      launch_template_specification {
        launch_template_id = aws_launch_template.my_launch_template.id
        version            = "$Latest"
      }
    }

    instances_distribution {
      spot_allocation_strategy                  = "lowest-price"
      on_demand_allocation_strategy             = "prioritized"
      on_demand_base_capacity                   = 0
      on_demand_percentage_above_base_capacity = 0
    }
  }

  vpc_zone_identifier  = ["subnet-xxxx"] # 替换为你的子网IDs

  tag {
    key                 = "AmazonECSManaged"
    value               = true
    propagate_at_launch = true
  }
}

resource "aws_ecs_task_definition" "my_task" {
  family                   = "ecs-demo-task"
  network_mode             = "awsvpc"
  requires_compatibilities = ["EC2"]
  cpu                      = "256"
  memory                   = "512"

  execution_role_arn = aws_iam_role.my_execution_role.arn
  
  container_definitions = <<DEFINITION
  [
    {
      "name": "ecs-demo",
      "image": "ecr_image_arn", # 替换为你的ECR镜像ARN
      "cpu": 256,
      "memory": 512,
      "essential": true,
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80
        }
      ]
    }
  ]
  DEFINITION
}
resource "aws_ecs_service" "my_ecs_service" {
  name            = "ecs-demo-service"
  cluster         = aws_ecs_cluster.my_cluster.id
  task_definition = aws_ecs_task_definition.my_task.arn
  desired_count   = 1
  launch_type     = "EC2"
  
  network_configuration {
    subnets         = ["subnet-xxxx"] # 替换为你的子网IDs
    security_groups = [aws_security_group.my_security_group.id]
  }

}

额外注意事项

  • 确认使用的AMI是ap-south-1区域的ECS优化AMI,避免因系统缺少ECS Agent导致连接失败
  • 替换脚本中所有vpc-xxxx、subnet-xxxx、ecr_image_arn为你的实际资源信息
  • 检查ECS实例角色权限,AmazonEC2ContainerServiceforEC2Role策略已包含实例与集群通信的必要权限

内容的提问来源于stack exchange,提问作者Butani Hardik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:25:56