在 AWS 上构建可复用的 AI 推理平台(基于 EC2 的实用方案与最佳实践)
作为偏售前的云工程师,我们经常需要在客户环境里快速搭建一个稳定、可扩展、成本可控的 AI 推理服务原型。本文给出一个面向中小型/企业试点的可复用解决方案,重点使用 EC2(含 GPU/CPU 节点)、容器化推理、VPC 网络规划、弹性伸缩与监控告警。方案易上手,便于在后续迭代中扩展为托管服务(如 SageMaker、ECS/EKS)。先决条件目录(核心步骤)创建 VPC、子网与路由创建 S3 存储
#作为偏售前的云工程师,我们经常需要在客户环境里快速搭建一个稳定、可扩展、成本可控的 AI 推理服务原型。本文给出一个面向中小型/企业试点的可复用解决方案,重点使用 EC2(含 GPU/CPU 节点)、容器化推理、VPC 网络规划、弹性伸缩与监控告警。方案易上手,便于在后续迭代中扩展为托管服务(如 SageMaker、ECS/EKS)。#
先决条件
- 已安装并配置 AWS CLI v2(aws configure)
- 有 IAM 用户/角色能创建 VPC、EC2、IAM、ALB、ECR、S3、Auto Scaling 等资源
- 有 Docker 用于构建并推送镜像(可选:在 CI 中完成)
- 本文以 us-east-1 为示例区域(按需修改 --region)
目录(核心步骤)
-
创建 VPC、子网与路由
-
创建 S3 存储并上传模型示例
-
创建 ECR 仓库并推送镜像(示例)
-
创建 IAM Role 与 Instance Profile(EC2 权限最小化)
-
创建 Security Groups(ALB 与 EC2)
-
创建 ACM 证书并验证(简化为 DNS 验证示例)
-
创建 ALB 与 Target Group、Listener
-
创建 Launch Template(包含用户数据脚本)
-
创建 Auto Scaling Group 并配置伸缩策略(基础)
-
配置 CloudWatch 基本告警
-
验证与清理
-
创建 VPC、子网与路由(两 AZ,公/私子网)
示例变量(替换为你的值)
- REGION=us-east-1
- VPC_CIDR=10.0.0.0/16
- AZ1=us-east-1a
- AZ2=us-east-1b
AWS CLI 命令:
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.{VpcId:VpcId}' --output text --region $REGION
记录 VPC_ID。
创建两个公有子网(用于 ALB)和两个私有子网(用于 EC2):
aws ec2 create-subnet --vpc-id <VPC_ID> --cidr-block 10.0.0.0/24 --availability-zone AZ1−−querySubnet.SubnetId−−outputtext−−regionAZ1−−querySubnet.SubnetId−−outputtext−−regionREGION
aws ec2 create-subnet --vpc-id <VPC_ID> --cidr-block 10.0.1.0/24 --availability-zone AZ2−−querySubnet.SubnetId−−outputtext−−regionAZ2−−querySubnet.SubnetId−−outputtext−−regionREGION
aws ec2 create-subnet --vpc-id <VPC_ID> --cidr-block 10.0.10.0/24 --availability-zone AZ1−−querySubnet.SubnetId−−outputtext−−regionAZ1−−querySubnet.SubnetId−−outputtext−−regionREGION
aws ec2 create-subnet --vpc-id <VPC_ID> --cidr-block 10.0.11.0/24 --availability-zone AZ2−−querySubnet.SubnetId−−outputtext−−regionAZ2−−querySubnet.SubnetId−−outputtext−−regionREGION
创建 Internet Gateway 并附加:
aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text --region REGIONawsec2attach−internet−gateway−−internet−gateway−id<IGWID>−−vpc−id<VPCID>−−regionREGIONawsec2attach−internet−gateway−−internet−gateway−id<IGWID>−−vpc−id<VPCID>−−regionREGION
为公有子网创建路由表并关联:
aws ec2 create-route-table --vpc-id <VPC_ID> --query RouteTable.RouteTableId --output text --region REGIONawsec2create−route−−route−table−id<RTBID>−−destination−cidr−block0.0.0.0/0−−gateway−id<IGWID>−−regionREGIONawsec2create−route−−route−table−id<RTBID>−−destination−cidr−block0.0.0.0/0−−gateway−id<IGWID>−−regionREGION
aws ec2 associate-route-table --route-table-id <RTB_ID> --subnet-id <PUBLIC_SUBNET_ID> --region $REGION
(为第二个公有子网也关联)
注意:按生产考虑可创建 NAT Gateway 放在公有子网,并将私有子网路由到 NAT;此处为简化略去 NAT 创建步骤(或在需要向 S3 / ECR 拉取时用 VPC Endpoint)。
- 创建 S3 存储并上传模型示例
创建 S3 桶并上传一个小模型文件(示例为 demo-model.tar.gz):
aws s3 mb s3://my-ai-model-bucket-(date+(date+REGION
aws s3 cp demo-model.tar.gz s3://my-ai-model-bucket-1234567890/models/demo-model.tar.gz
建议:启用桶加密(默认 SSE)和版本控制:
aws s3api put-bucket-encryption --bucket --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}' --region REGIONawss3apiput−bucket−versioning−−bucket<BUCKET>−−versioning−configurationStatus=Enabled−−regionREGIONawss3apiput−bucket−versioning−−bucket<BUCKET>−−versioning−configurationStatus=Enabled−−regionREGION
- 创建 ECR 仓库并推送镜像(示例)
创建仓库:
aws ecr create-repository --repository-name ai-inference --region REGION登录ECR(CLI提示docker登录):awsecrget−login−password−−regionREGION登录ECR(CLI提示docker登录):awsecrget−login−password−−regionREGION | docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.$REGION.amazonaws.com
构建并推送镜像(在本地有 Dockerfile):
docker build -t ai-inference:latest .
docker tag ai-inference:latest <ACCOUNT_ID>.dkr.ecr.REGION.amazonaws.com/ai−inference:latestdockerpush<ACCOUNTID>.dkr.ecr.REGION.amazonaws.com/ai−inference:latestdockerpush<ACCOUNTID>.dkr.ecr.REGION.amazonaws.com/ai-inference:latest
镜像应包含:推理服务器(Flask/FastAPI/uvicorn)、/health 健康端点、启动脚本支持从 S3 拉模型并放到 /opt/model。
- 创建 IAM Role 与 Instance Profile(最小权限)
创建信任策略文件(ec2-trust.json)内容:
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}
创建角色:
aws iam create-role --role-name EC2InferenceRole --assume-role-policy-document file://ec2-trust.json
附加策略(最小权限,示例为读取 S3、拉 ECR 镜像、写 CloudWatch Logs):
创建自定义策略文档(InferencePolicy.json),示例包含:
- s3:GetObject s3:ListBucket 指向模型路径
- ecr:GetAuthorizationToken ecr:BatchGetImage ecr:GetDownloadUrlForLayer
- logs:CreateLogGroup logs:CreateLogStream logs:PutLogEvents
- cloudwatch:PutMetricData
创建并附加策略:
aws iam put-role-policy --role-name EC2InferenceRole --policy-name InferencePolicy --policy-document file://InferencePolicy.json
创建 instance-profile 并关联:
aws iam create-instance-profile --instance-profile-name EC2InferenceInstanceProfile
aws iam add-role-to-instance-profile --instance-profile-name EC2InferenceInstanceProfile --role-name EC2InferenceRole
- 创建 Security Groups(ALB 与 EC2)
创建 ALB SG(允许 443 来自公网):
aws ec2 create-security-group --group-name ALB-SG --description "ALB SG" --vpc-id <VPC_ID> --region REGIONawsec2authorize−security−group−ingress−−group−id<ALBSGID>−−protocoltcp−−port443−−cidr0.0.0.0/0−−regionREGIONawsec2authorize−security−group−ingress−−group−id<ALBSGID>−−protocoltcp−−port443−−cidr0.0.0.0/0−−regionREGION
创建 EC2 SG(允许 ALB SG 在 8080 端口访问):
aws ec2 create-security-group --group-name EC2-SG --description "EC2 inference SG" --vpc-id <VPC_ID> --region REGIONawsec2authorize−security−group−ingress−−group−id<EC2SGID>−−protocoltcp−−port8080−−source−group<ALBSGID>−−regionREGIONawsec2authorize−security−group−ingress−−group−id<EC2SGID>−−protocoltcp−−port8080−−source−group<ALBSGID>−−regionREGION
允许出站到 S3/ECR(通常默认允许全部出站)。
- 创建 ACM 证书并验证(DNS 验证,需 Route53)
如果你的域在 Route53,DNS 验证可自动完成。示例:
aws acm request-certificate --domain-name inference.example.com --validation-method DNS --idempotency-token 1234 --region $REGION
记录返回的 CertificateArn。随后获取验证记录并在 Route53 中创建相应 CNAME(此步骤可在控制台或通过 cli 创建)。
注意:如果只是演示,可在 ALB Listener 使用 HTTP(80)跳过证书,但生产请务必启用 TLS。
- 创建 ALB 与 Target Group、Listener
创建 ALB(放在公有子网):
aws elbv2 create-load-balancer --name ai-inference-alb --subnets <PUB_SUBNET1> <PUB_SUBNET2> --security-groups <ALB_SG_ID> --scheme internet-facing --type application --region $REGION
记录 LoadBalancerArn 与 DNS 名称。
创建 Target Group(HTTP 8080,v2 ALB 健康检查 /health):
aws elbv2 create-target-group --name ai-inference-tg --protocol HTTP --port 8080 --vpc-id <VPC_ID> --health-check-protocol HTTP --health-check-path /health --region $REGION
创建 Listener(HTTPS 443 指向 Target Group;若未配置证书,可创建 HTTP 80 Listener):
aws elbv2 create-listener --load-balancer-arn <LB_ARN> --protocol HTTP --port 80 --default-actions Type=forward,TargetGroupArn=<TG_ARN> --region $REGION
(若使用 ACM 证书):使用 --protocol HTTPS --port 443 --certificates CertificateArn=<CERT_ARN>
- 创建 Launch Template(用户数据:拉镜像、从 S3 下载模型并运行容器)
示例 user-data(Base64 编码前的脚本,简化为 Ubuntu/Docker):
#!/bin/bash
set -e
REGION=us-east-1
ECR_REGISTRY=<ACCOUNT_ID>.dkr.ecr.$REGION.amazonaws.com
IMAGE=ai-inference:latest
MODEL_S3_BUCKET=
MODEL_S3_KEY=models/demo-model.tar.gz
MODEL_DIR=/opt/model
更新并安装 docker
apt-get update
apt-get install -y docker.io awscli
systemctl enable docker && systemctl start docker
登录 ECR
aws ecr get-login-password --region REGION∣dockerlogin−−usernameAWS−−password−stdinREGION∣dockerlogin−−usernameAWS−−password−stdinECR_REGISTRY
拉镜像
docker pull ECRREGISTRY/ECRREGISTRY/IMAGE
下载模型
mkdir -p MODELDIRawss3cps3://MODELDIRawss3cps3://MODEL_S3_BUCKET/MODELS3KEYMODELS3KEYMODEL_DIR/demo-model.tar.gz
tar -xzf MODELDIR/demo−model.tar.gz−CMODELDIR/demo−model.tar.gz−CMODEL_DIR
运行容器(暴露 8080)
docker run -d --name inference -p 8080:8080 -e MODEL_PATH=MODELDIRMODELDIRECR_REGISTRY/$IMAGE
将此脚本保存为 user-data.txt。创建 Launch Template(选择对应 AMI,如 Amazon Linux 2 AMI 或 Ubuntu):
aws ec2 create-launch-template --launch-template-name ai-inference-lt --version-description "v1" --launch-template-data file://launch-template-data.json --region $REGION
launch-template-data.json 示例要包含:
{
"ImageId":"<AMI_ID>",
"InstanceType":"t3.medium",
"IamInstanceProfile":{"Name":"EC2InferenceInstanceProfile"},
"SecurityGroupIds":["<EC2_SG_ID>"],
"UserData":"<BASE64_ENCODED_USER_DATA>"
}
注意:若使用 GPU 实例需使用带 NVIDIA 驱动的 AMI 或在 user-data 中安装驱动(会增加启动时间)。也可使用自定义 AMI 预装驱动与 Docker。
- 创建 Auto Scaling Group 并基本伸缩策略
创建 ASG,指定最小/最大/期望实例数,并加入 Target Group:
aws autoscaling create-auto-scaling-group --auto-scaling-group-name ai-inference-asg --launch-template "LaunchTemplateName=ai-inference-lt,Version=1" --min-size 1 --max-size 4 --desired-capacity 1 --vpc-zone-identifier "<PRIV_SUBNET1>,<PRIV_SUBNET2>" --target-group-arns <TG_ARN> --region $REGION
创建基于 ALB 请求数的伸缩策略(简单示例:每个目标平均请求数 > 100 时扩容):
aws autoscaling put-scaling-policy --auto-scaling-group-name ai-inference-asg --policy-name scale-out-policy --policy-type TargetTrackingScaling --target-tracking-configuration '{"PredefinedMetricSpecification":{"PredefinedMetricType":"ALBRequestCountPerTarget"},"TargetValue":100.0}' --region $REGION
类似地创建 scale-in(Auto Scaling 会自动管理缩减)。
注意:更稳定的伸缩通常基于平均 CPU、GPU 利用或自定义指标(如推理延时)。GPU 利用需自定义 CloudWatch metrics(可通过 CloudWatch agent 或脚本上报)。
- 配置 CloudWatch 基本告警(示例:高 95th 延时报警)
首先,应用需要将延时以自定义 MetricPut 上报到 CloudWatch(示例代码未列出)。这里示范一个 CPU 高利用报警:
aws cloudwatch put-metric-alarm --alarm-name high-cpu-asg --metric-name CPUUtilization --namespace AWS/EC2 --statistic Average --period 300 --evaluation-periods 2 --threshold 75 --comparison-operator GreaterThanThreshold --dimensions Name=AutoScalingGroupName,Value=ai-inference-asg --alarm-actions <SNS_TOPIC_ARN> --region $REGION
你可以创建 SNS topic 并订阅你的邮件:
aws sns create-topic --name ops-alerts
aws sns subscribe --topic-arn <SNS_ARN> --protocol email --notification-endpoint you@example.com
- 验证
- 等待 ALB 健康检查通过(在 ELB 控制台或 aws elbv2 describe-target-health 查看)。
- 访问 http://<ALB_DNS>/ 假如 listener 为 HTTP,或 https:/// 若已配置 ACM。
- 测试推理端点:curl http://<ALB_DNS>/predict -d '{"input":...}' -H 'Content-Type: application/json'
清理提示(节省成本)
创建资源后若仅为测试请记得删除以避免费用:
- 删除 ASG(autoscaling delete-auto-scaling-group)
- 删除 Launch Template
- 删除 ALB(elbv2 delete-load-balancer)
- 删除 Target Group
- 删除 EC2 实例、Security Groups、IAM roles & instance profile
- 删除 S3 桶(先删除对象)
- 删除 ECR repo(或保留)
脚本化清理或使用标签便于管理。
可复用与扩展建议(实践最佳做法)
- 参数化脚本:将上面命令用 Bash 脚本或 Makefile 封装,使用变量(VPC、域名、镜像标签、模型 S3 路径)。
- 使用 Launch Template + AMI:为降低冷启动时间,使用自定义 AMI 预装 Docker 与依赖(及 NVIDIA 驱动)。
- 混合部署:CPU / GPU 分开部署,ALB 可基于路径/Host 路由到不同 Target Group。
- CI/CD:在镜像更新时用 CI 推送 ECR,并通过 autoscaling start-instance 或更新 Launch Template 触发平滑滚动更新。
- 监控与追踪:在容器内使用 CloudWatch Agent 或 OpenTelemetry 上报 p95/p99 延时以作为伸缩与告警依据。
- 最小权限:IAM 策略尽量精细到具体 S3 路径与 ECR repo。
示例脚本资源(可作为下一步)
- 一个参数化的 bootstrap.sh,执行上文所有 CLI 步骤(需要做错误检查与幂等性)
- 一个 Dockerfile 模板(包含 /health 与 S3 模型拉取逻辑)
- 一个 CloudWatch 自定义指标上报示例(Python 简单脚本上报推理延时)
结语
本文通过可执行的 AWS CLI 命令序列,覆盖了从网络、安全、镜像、模型分发到自动伸缩与基本监控的端到端流程,适合售前快速搭建 PoC 或交付基础可复用模板。你可以把这些命令脚本化并参数化成一个小型部署工具或制作成 Terraform/CloudFormation 模板以便长期复用。
更多推荐



所有评论(0)