使用CDK构建ALB + Fargate
发布于
2025年4月27日
更新于
2025年4月27日
15
分钟阅读
AWS
在现代服务架构中,借助容器化与 serverless 模式可以大幅简化运维工作。本文示例展示如何使用 AWS CDK(v2)通过 Fargate 部署 serverless服务。
1. 项目结构概览
在开始之前,假设你已经安装好 AWS CDK 并初始化了一个 TypeScript 项目。目录结构示例如下:
my-cdk-project/
├── bin/
│ └── my-cdk-project.ts // CDK 应用入口
├── lib/
│ └── server-stack.ts // 我们接下来要编写的 Stack
├── package.json
└── tsconfig.json
2. 核心 CDK 代码
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as log from 'aws-cdk-lib/aws-logs';
import { Construct } from 'constructs';
export class ServerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 1. 加载已有网络与安全组资源
const albSg = ec2.SecurityGroup.fromSecurityGroupId(this, 'alb-sg', 'alb-sg-id');
const ecsSg = ec2.SecurityGroup.fromSecurityGroupId(this, 'ecs-sg', 'ecs-sg-id');
const vpc = ec2.Vpc.fromLookup(this, 'vpc', { vpcId: 'vpc-id' });
const albSubnetA = ec2.Subnet.fromSubnetId(this, 'alb-subnet-a', 'alb-subnet-a-id');
const albSubnetC = ec2.Subnet.fromSubnetId(this, 'alb-subnet-c', 'alb-sunbet-c-id');
const ecsSubnetA = ec2.Subnet.fromSubnetId(this, 'ecs-subnet-a', 'ecs-subnet-a-id');
const ecsSubnetC = ec2.Subnet.fromSubnetId(this, 'ecs-subnet-c', 'ecs-sunbet-c-id');
// 2. 引入已有 IAM 角色
const taskRole = iam.Role.fromRoleArn(this, 'task-role', 'task-role-arn', {
mutable: false,
});
const taskExecutionRole = iam.Role.fromRoleArn(this, 'task-execution-role', 'task-execution-role-arn', {
mutable: false,
});
// 3. 创建 ECS 集群
const cluster = new ecs.Cluster(this, 'ecs-cluster', {
vpc: vpc,
clusterName: 'ecs-cluster',
});
// 4. 创建任务定义
const taskDefinition = new ecs.FargateTaskDefinition(this, 'task-definition', {
taskRole: taskRole,
executionRole: taskExecutionRole,
cpu: 512,
memoryLimitMiB: 1024,
});
// 5. 引入 ECR Repository
const repository = ecr.Repository.fromRepositoryArn(this, 'ecr-repository', 'ecr-arn');
// 6. 创建log group
const logGroup = new log.LogGroup(this, 'server-log', {
logGroupName: '/aws/server-log',
retention: log.RetentionDays.THREE_YEARS,
});
// 7. 配置容器镜像
taskDefinition.addContainer('task', {
image: ecs.ContainerImage.fromEcrRepository(repository, 'xxxxx'),
logging: ecs.LogDriver.awsLogs({
logGroup: logGroup,
streamPrefix: 'api',
}),
portMappings: [{ containerPort: 80 }],
environment: {
NODE_ENV: 'it',
},
readonlyRootFilesystem: true,
});
// 8. 部署 Fargate 服务
const service = new ecs.FargateService(this, 'service', {
serviceName: 'server_name',
cluster: cluster,
taskDefinition: taskDefinition,
securityGroups: [ecsSg],
vpcSubnets: { subnets: [ecsSubnetA, ecsSubnetC] },
});
// 9. 生成应用型负载均衡(ALB)
const alb = new elbv2.ApplicationLoadBalancer(this, `alb`, {
loadBalancerName: 'alb',
securityGroup: albSg,
vpc: vpc,
vpcSubnets: { subnets: [albSubnetA, albSubnetC] },
});
// 10. 创建目标组与健康检查
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'alb-tg', {
targetGroupName: '',
vpc: vpc,
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
targetType: elbv2.TargetType.IP,
crossZoneEnabled: true,
healthCheck: {
path: '/health',
healthyHttpCodes: '200',
},
targets: [service],
});
// 11. 添加监听器与路由规则
const listener = alb.addListener('alb-listener', {
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
open: false,
defaultAction: elbv2.ListenerAction.fixedResponse(404, { contentType: 'application/json' }),
});
new elbv2.CfnListenerRule(this, 'server-rule', {
listenerArn: listener.listenerArn,
priority: 1,
conditions: [
{
field: 'path-pattern',
values: ['/api/*'], // 在这里我们可以指定路由规则,只将符合规则的请求转发到Fargate
},
],
actions: [{ type: 'forward', targetGroupArn: targetGroup.targetGroupArn }],
});
}
}
3. 总结
通过本文示例,你可以快速复用已有的 VPC、子网、安全组、IAM 角色、ECR 仓库和日志组,借助 AWS CDK 一键式部署:
- 高可用:多可用区负载均衡 + Fargate 无服务器服务
- 安全:细粒度安全组、只读容器文件系统
- 可观测:CloudWatch Logs 实时日志
将此模板进一步扩展,可支持 HTTPS、自动扩缩容、蓝绿发布等多种生产级特性。欢迎在评论区分享你的优化方案!