168 lines
5.8 KiB
TypeScript
168 lines
5.8 KiB
TypeScript
import * as cdk from '@aws-cdk/core';
|
|
import * as ec2 from "@aws-cdk/aws-ec2"; // Allows working with EC2 and VPC resources
|
|
import * as iam from "@aws-cdk/aws-iam"; // Allows working with IAM resources
|
|
import * as ecs from "@aws-cdk/aws-ecs";
|
|
import * as cwl from "@aws-cdk/aws-logs";
|
|
import * as elb from "@aws-cdk/aws-elasticloadbalancingv2"
|
|
import * as ecr_assets from '@aws-cdk/aws-ecr-assets';
|
|
import * as route53 from "@aws-cdk/aws-route53";
|
|
import * as route53_targets from "@aws-cdk/aws-route53-targets"
|
|
import * as path from "path"; // Helper for working with file paths
|
|
|
|
export class WarpStack extends cdk.Stack {
|
|
constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
|
|
super(scope, id, props);
|
|
|
|
//1. Create VPC
|
|
const vpc = new ec2.Vpc(this, 'VPC');
|
|
|
|
//2. Creation of Execution Role for our task
|
|
const execRole = new iam.Role(this, 'warp-exec-role', {
|
|
roleName: 'warp-exec-role', assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com')
|
|
})
|
|
|
|
//3. Adding permissions to the above created role...basically giving permissions to ECR image and Cloudwatch logs
|
|
execRole.addToPolicy(new iam.PolicyStatement({
|
|
actions: [
|
|
"ecr:GetAuthorizationToken",
|
|
"ecr:BatchCheckLayerAvailability",
|
|
"ecr:GetDownloadUrlForLayer",
|
|
"ecr:BatchGetImage",
|
|
"logs:CreateLogStream",
|
|
"logs:PutLogEvents"
|
|
], effect: iam.Effect.ALLOW, resources: ["*"]
|
|
}));
|
|
|
|
//4. Create the ECS fargate cluster
|
|
const cluster = new ecs.Cluster(this, 'warp-cluster', { vpc, clusterName: "warp-cluster" });
|
|
|
|
//5. Create a task definition for our cluster to invoke a task
|
|
const taskDef = new ecs.FargateTaskDefinition(this, "warp-task", {
|
|
family: 'warp-task',
|
|
executionRole: execRole,
|
|
taskRole: execRole,
|
|
volumes: [{ name: "cert" }],
|
|
});
|
|
|
|
//6. Create log group for our task to put logs
|
|
const log_group = cwl.LogGroup.fromLogGroupName(this, 'warp-log-group', '/ecs/warp-task');
|
|
|
|
const log = new ecs.AwsLogDriver({
|
|
logGroup: log_group ? log_group : new cwl.LogGroup(this, 'warp-log-group', { logGroupName: '/ecs/warp-task' }),
|
|
streamPrefix: 'ecs'
|
|
})
|
|
|
|
// ?? Build the docker images
|
|
const player_image = new ecr_assets.DockerImageAsset(this, 'warp-player-image', {
|
|
directory: path.join(__dirname, '/../../player'),
|
|
});
|
|
|
|
const server_image = new ecr_assets.DockerImageAsset(this, 'warp-server-image', {
|
|
directory: path.join(__dirname, '/../../server'),
|
|
});
|
|
|
|
/*
|
|
const media_image = new ecr_assets.DockerImageAsset(this, 'warp-media-image', {
|
|
directory: path.join(__dirname, '/../../media'),
|
|
});
|
|
*/
|
|
|
|
//7. Create container for the task definition from ECR image
|
|
var player_container = taskDef.addContainer("warp-player-container", {
|
|
image: ecs.ContainerImage.fromDockerImageAsset(player_image),
|
|
logging: log,
|
|
portMappings: [{
|
|
containerPort: 80,
|
|
hostPort: 80,
|
|
protocol: ecs.Protocol.TCP
|
|
}, {
|
|
containerPort: 443,
|
|
hostPort: 443,
|
|
protocol: ecs.Protocol.TCP
|
|
}],
|
|
})
|
|
|
|
var server_container = taskDef.addContainer("warp-server-container", {
|
|
image: ecs.ContainerImage.fromDockerImageAsset(server_image),
|
|
logging: log,
|
|
portMappings: [{
|
|
containerPort: 443,
|
|
hostPort: 443,
|
|
protocol: ecs.Protocol.UDP
|
|
}],
|
|
})
|
|
|
|
//9. Create the NLB using the above VPC.
|
|
const nlb = new elb.NetworkLoadBalancer(this, 'warp-nlb', {
|
|
loadBalancerName: 'warp-nlb',
|
|
vpc,
|
|
internetFacing: true,
|
|
});
|
|
|
|
// ?? Create a DNS entry for the nlb
|
|
const zone = route53.HostedZone.fromHostedZoneAttributes(this, "warp-zone", {
|
|
hostedZoneId: "Z0166044CZ3H7MIDXT7P", // Unfortunately we need to hard-code the route53 zone
|
|
zoneName: "quic.video",
|
|
});
|
|
|
|
const record = new route53.ARecord(this, "warp-record", {
|
|
zone: zone,
|
|
target: route53.RecordTarget.fromAlias(new route53_targets.LoadBalancerTarget(nlb)),
|
|
})
|
|
|
|
// Route based on latency.
|
|
const recordSet = (record.node.defaultChild as route53.CfnRecordSet);
|
|
recordSet.region = props.env?.region;
|
|
recordSet.setIdentifier = props.env?.region;
|
|
|
|
//10. Add a listener on a particular port for the NLB
|
|
const http_listener = nlb.addListener('warp-http-listener', {
|
|
protocol: elb.Protocol.TCP,
|
|
port: 80,
|
|
});
|
|
|
|
const https_listener = nlb.addListener('warp-https-listener', {
|
|
protocol: elb.Protocol.TCP_UDP,
|
|
port: 443,
|
|
});
|
|
|
|
//11. Create your own security Group using VPC
|
|
const sg = new ec2.SecurityGroup(this, 'warp-player-sg', {
|
|
securityGroupName: "warp-player-sg",
|
|
vpc: vpc,
|
|
allowAllOutbound: true,
|
|
});
|
|
|
|
//12. Add IngressRule to access the docker image
|
|
sg.addIngressRule(ec2.Peer.ipv4('0.0.0.0/0'), ec2.Port.tcp(80), 'HTTP');
|
|
sg.addIngressRule(ec2.Peer.ipv4('0.0.0.0/0'), ec2.Port.tcp(443), 'HTTPS');
|
|
sg.addIngressRule(ec2.Peer.ipv4('0.0.0.0/0'), ec2.Port.udp(443), 'HTTP/3');
|
|
|
|
//13. Create Fargate Service from cluster, task definition and the security group
|
|
const service = new ecs.FargateService(this, 'warp-service', {
|
|
cluster: cluster,
|
|
taskDefinition: taskDef,
|
|
assignPublicIp: true,
|
|
serviceName: "warp-service",
|
|
securityGroups: [sg],
|
|
});
|
|
|
|
//14. Add fargate service to the listener
|
|
http_listener.addTargets('warp-http-target', {
|
|
targetGroupName: 'warp-http-target',
|
|
protocol: elb.Protocol.TCP,
|
|
port: 80,
|
|
targets: [service],
|
|
deregistrationDelay: cdk.Duration.seconds(300)
|
|
});
|
|
|
|
https_listener.addTargets('warp-https-target', {
|
|
targetGroupName: 'warp-https-target',
|
|
protocol: elb.Protocol.TCP_UDP,
|
|
port: 443,
|
|
targets: [service],
|
|
deregistrationDelay: cdk.Duration.seconds(300)
|
|
});
|
|
}
|
|
}
|