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

如何通过Terraform在单个AWS VPC中创建多台EC2实例?

问题描述
  • 能否通过Terraform在单个AWS VPC中创建多台EC2实例?
  • 此前每次创建实例都新建VPC,耗尽AWS区域5个VPC配额后无法创建第6台实例。
  • 尝试导入现有VPC及关联资源后,出现SSH无法访问实例、user_data中的setting_instance.py脚本不执行的问题。
  • 需要最大化复用VPC、子网等基础资源的方案,以及现有Terraform代码的优化建议。
解决方案与代码优化

一、单个VPC中创建多台EC2实例的核心思路

复用VPC、子网、安全组、路由表等基础网络资源,仅对EC2实例、弹性IP(如需要)等实例级资源进行批量创建,使用Terraform的count或for_each实现批量部署。

二、解决SSH访问与user_data执行问题

SSH无法访问的排查点

  1. 确认安全组的22端口规则已正确关联到实例所在子网/实例,源地址配置符合需求(建议限制为你的公网IP,而非全开放)。
  2. 实例需具备公网IP:可通过子网开启map_public_ip_on_launch自动分配,或绑定弹性IP。
  3. 确认密钥对key_name与实例所在区域匹配,本地私钥文件权限设置为600。
  4. 导入现有资源时,需确保路由表已关联子网、互联网网关已绑定VPC,实例出站流量正常。

user_data脚本不执行的解决方法

  1. Ubuntu系统依赖cloud-init处理user_data,确保脚本开头的#!/bin/bash格式正确。
  2. 若setting_instance.py未预存在实例中,需先通过user_data下载脚本(例如从S3拉取),示例:
    #!/bin/bash
    apt update && apt install -y python3
    aws s3 cp s3://your-bucket/setting_instance.py /home/ubuntu/
    python3 /home/ubuntu/setting_instance.py
    
  3. 查看cloud-init日志排查问题:cat /var/log/cloud-init.log或cat /var/log/cloud-init-output.log。

三、Terraform代码优化建议

  1. 移除硬编码凭证:不要在provider中直接写access_key和secret_key,改用环境变量AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY或AWS凭证文件~/.aws/credentials。
  2. 简化网络配置:无需手动创建网络接口,EC2实例可直接关联子网和安全组,自动分配私IP。
  3. 批量创建实例:使用count参数批量生成多台实例,复用基础资源。
  4. 弹性IP关联优化:直接将弹性IP绑定到EC2实例,无需通过网卡中转。
  5. 移除冗余依赖:Terraform会自动处理资源依赖,无需手动添加depends_on(除非特殊场景)。

优化后的示例代码

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# AWS Provider配置(使用环境变量或凭证文件,避免硬编码)
provider "aws" {
  region = "us-east-2"
}

# 1. 创建VPC
resource "aws_vpc" "prod-vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "production"
  }
}

# 2. 创建互联网网关
resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.prod-vpc.id

  tags = {
    Name = "prod-igw"
  }
}

# 3. 创建路由表
resource "aws_route_table" "prod-route-table" {
  vpc_id = aws_vpc.prod-vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }

  tags = {
    Name = "Prod"
  }
}

# 4. 创建子网(开启自动分配公网IP)
resource "aws_subnet" "prod-subnet" {
  vpc_id                  = aws_vpc.prod-vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-2a"
  map_public_ip_on_launch = true # 实例创建时自动分配公网IP

  tags = {
    Name = "prod-subnet"
  }
}

# 5. 子网关联路由表
resource "aws_route_table_association" "prod-subnet-assoc" {
  subnet_id      = aws_subnet.prod-subnet.id
  route_table_id = aws_route_table.prod-route-table.id
}

# 6. 安全组配置
resource "aws_security_group" "allow_web" {
  name        = "allow_web_traffic"
  description = "Allow Web inbound traffic"
  vpc_id      = aws_vpc.prod-vpc.id

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "Custom Port"
    from_port   = 8000
    to_port     = 8000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"] # 建议改为你的公网IP,提升安全性
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_web"
  }
}

# 7. 批量创建EC2实例(示例创建3台)
resource "aws_instance" "web-server" {
  count             = 3 # 实例数量
  ami               = var.AMI_ID
  instance_type     = "g4dn.xlarge"
  availability_zone = "us-east-2a"
  key_name          = "us-east-2"
  subnet_id         = aws_subnet.prod-subnet.id
  vpc_security_group_ids = [aws_security_group.allow_web.id]

  root_block_device {
    volume_size = "200"
  }

  iam_instance_profile = aws_iam_instance_profile.training_profile.name

  user_data = <<-EOF
              #!/bin/bash
              # 确保python3已安装
              apt update && apt install -y python3
              # 示例:若脚本在S3,先下载再执行
              # aws s3 cp s3://your-bucket/setting_instance.py /home/ubuntu/
              python3 /home/ubuntu/setting_instance.py
              EOF

  tags = {
    Name = "${var.INSTANCE_NAME}-${count.index + 1}"
  }
}

# 8. 批量创建弹性IP(可选)
resource "aws_eip" "web-server-eip" {
  count               = 3
  instance            = aws_instance.web-server[count.index].id
  vpc                 = true

  tags = {
    Name = "${var.INSTANCE_NAME}-eip-${count.index + 1}"
  }
}

# 输出所有实例的公网IP
output "server_public_ips" {
  value = [for instance in aws_instance.web-server : instance.public_ip]
}

# 输出所有弹性IP(如果使用)
output "eip_addresses" {
  value = [for eip in aws_eip.web-server-eip : eip.public_ip]
}

内容的提问来源于stack exchange,提问作者kiran pradeep

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:30:39