Initial work on CDK+fargate.
This commit is contained in:
parent
4c5246e5fa
commit
be3f44c7b1
|
@ -0,0 +1,8 @@
|
|||
*.js
|
||||
!jest.config.js
|
||||
*.d.ts
|
||||
node_modules
|
||||
|
||||
# CDK asset staging directory
|
||||
.cdk.staging
|
||||
cdk.out
|
|
@ -0,0 +1,6 @@
|
|||
*.ts
|
||||
!*.d.ts
|
||||
|
||||
# CDK asset staging directory
|
||||
.cdk.staging
|
||||
cdk.out
|
|
@ -0,0 +1,14 @@
|
|||
# Welcome to your CDK TypeScript project
|
||||
|
||||
This is a blank project for CDK development with TypeScript.
|
||||
|
||||
The `cdk.json` file tells the CDK Toolkit how to execute your app.
|
||||
|
||||
## Useful commands
|
||||
|
||||
* `npm run build` compile typescript to js
|
||||
* `npm run watch` watch for changes and compile
|
||||
* `npm run test` perform the jest unit tests
|
||||
* `cdk deploy` deploy this stack to your default AWS account/region
|
||||
* `cdk diff` compare deployed stack with current state
|
||||
* `cdk synth` emits the synthesized CloudFormation template
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env node
|
||||
import 'source-map-support/register';
|
||||
import * as cdk from '@aws-cdk/core';
|
||||
import { WarpStack } from '../lib/warp';
|
||||
|
||||
const app = new cdk.App();
|
||||
|
||||
new WarpStack(app, 'warp-us-east-1', {
|
||||
env: { account: '864566598233', region: 'us-east-1' },
|
||||
});
|
||||
|
||||
new WarpStack(app, 'warp-us-west-2', {
|
||||
env: { account: '864566598233', region: 'us-west-2' },
|
||||
});
|
||||
|
||||
app.synth();
|
|
@ -0,0 +1,105 @@
|
|||
{
|
||||
"vpc-provider:account=864566598233:filter.isDefault=true:region=us-east-1:returnAsymmetricSubnets=true": {
|
||||
"vpcId": "vpc-0eb5406e69a058c21",
|
||||
"vpcCidrBlock": "172.31.0.0/16",
|
||||
"availabilityZones": [],
|
||||
"subnetGroups": [
|
||||
{
|
||||
"name": "Public",
|
||||
"type": "Public",
|
||||
"subnets": [
|
||||
{
|
||||
"subnetId": "subnet-098223d57b90bc5ba",
|
||||
"cidr": "172.31.0.0/20",
|
||||
"availabilityZone": "us-east-1a",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-0f85396c1e654088a",
|
||||
"cidr": "172.31.80.0/20",
|
||||
"availabilityZone": "us-east-1b",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-0da18611f81d0ee65",
|
||||
"cidr": "172.31.16.0/20",
|
||||
"availabilityZone": "us-east-1c",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-04ec9401177026153",
|
||||
"cidr": "172.31.32.0/20",
|
||||
"availabilityZone": "us-east-1d",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-09990358c6611a867",
|
||||
"cidr": "172.31.48.0/20",
|
||||
"availabilityZone": "us-east-1e",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-09eefe16a158ac97d",
|
||||
"cidr": "172.31.64.0/20",
|
||||
"availabilityZone": "us-east-1f",
|
||||
"routeTableId": "rtb-00247d339210de603"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"vpc-provider:account=864566598233:filter.isDefault=true:region=us-west-2:returnAsymmetricSubnets=true": {
|
||||
"vpcId": "vpc-0e1c6b8dc284b5ea8",
|
||||
"vpcCidrBlock": "172.31.0.0/16",
|
||||
"availabilityZones": [],
|
||||
"subnetGroups": [
|
||||
{
|
||||
"name": "Public",
|
||||
"type": "Public",
|
||||
"subnets": [
|
||||
{
|
||||
"subnetId": "subnet-0b20049ea38baab49",
|
||||
"cidr": "172.31.16.0/20",
|
||||
"availabilityZone": "us-west-2a",
|
||||
"routeTableId": "rtb-02fa3d3e8c3c073a2"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-035cb5403ca3a6fd0",
|
||||
"cidr": "172.31.32.0/20",
|
||||
"availabilityZone": "us-west-2b",
|
||||
"routeTableId": "rtb-02fa3d3e8c3c073a2"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-08a943f1d7ffe1269",
|
||||
"cidr": "172.31.0.0/20",
|
||||
"availabilityZone": "us-west-2c",
|
||||
"routeTableId": "rtb-02fa3d3e8c3c073a2"
|
||||
},
|
||||
{
|
||||
"subnetId": "subnet-05ce9ae279372b111",
|
||||
"cidr": "172.31.48.0/20",
|
||||
"availabilityZone": "us-west-2d",
|
||||
"routeTableId": "rtb-02fa3d3e8c3c073a2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"acknowledged-issue-numbers": [
|
||||
19836
|
||||
],
|
||||
"availability-zones:account=864566598233:region=us-east-1": [
|
||||
"us-east-1a",
|
||||
"us-east-1b",
|
||||
"us-east-1c",
|
||||
"us-east-1d",
|
||||
"us-east-1e",
|
||||
"us-east-1f"
|
||||
],
|
||||
"availability-zones:account=864566598233:region=us-west-2": [
|
||||
"us-west-2a",
|
||||
"us-west-2b",
|
||||
"us-west-2c",
|
||||
"us-west-2d"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"app": "npx ts-node --prefer-ts-exts bin/deploy.ts",
|
||||
"watch": {
|
||||
"include": [
|
||||
"**"
|
||||
],
|
||||
"exclude": [
|
||||
"README.md",
|
||||
"cdk*.json",
|
||||
"**/*.d.ts",
|
||||
"**/*.js",
|
||||
"tsconfig.json",
|
||||
"package*.json",
|
||||
"yarn.lock",
|
||||
"node_modules",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
"context": {
|
||||
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
||||
"@aws-cdk/core:checkSecretUsage": true,
|
||||
"@aws-cdk/core:target-partitions": [
|
||||
"aws",
|
||||
"aws-cn"
|
||||
],
|
||||
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
||||
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
||||
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
|
||||
"@aws-cdk/aws-iam:minimizePolicies": true,
|
||||
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
||||
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
||||
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
||||
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
||||
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
|
||||
"@aws-cdk/core:enablePartitionLiterals": true,
|
||||
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
|
||||
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
|
||||
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/test'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest'
|
||||
}
|
||||
};
|
|
@ -0,0 +1,167 @@
|
|||
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)
|
||||
});
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "deploy",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"deploy": "bin/deploy.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w",
|
||||
"test": "jest",
|
||||
"cdk": "cdk"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.3",
|
||||
"@types/node": "18.11.9",
|
||||
"aws-cdk": "^2.54.0",
|
||||
"jest": "^29.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-cdk/aws-ec2": "^1.191.0",
|
||||
"@aws-cdk/aws-ecs": "^1.191.0",
|
||||
"@aws-cdk/aws-ecs-patterns": "^1.191.0",
|
||||
"@aws-cdk/aws-iam": "^1.191.0",
|
||||
"@aws-cdk/aws-s3-assets": "^1.191.0",
|
||||
"aws-cdk-lib": "^2.63.0",
|
||||
"constructs": "^10.0.0",
|
||||
"source-map-support": "^0.5.21"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// import * as cdk from 'aws-cdk-lib';
|
||||
// import { Template } from 'aws-cdk-lib/assertions';
|
||||
// import * as Deploy from '../lib/deploy-stack';
|
||||
|
||||
// example test. To run these tests, uncomment this file along with the
|
||||
// example resource in lib/deploy-stack.ts
|
||||
test('SQS Queue Created', () => {
|
||||
// const app = new cdk.App();
|
||||
// // WHEN
|
||||
// const stack = new Deploy.DeployStack(app, 'MyTestStack');
|
||||
// // THEN
|
||||
// const template = Template.fromStack(stack);
|
||||
|
||||
// template.hasResourceProperties('AWS::SQS::Queue', {
|
||||
// VisibilityTimeout: 300
|
||||
// });
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es2020"
|
||||
],
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitThis": true,
|
||||
"alwaysStrict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"cdk.out"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
FROM ubuntu
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y nginx certbot python3-certbot-nginx
|
||||
|
||||
# Contains the final certificates created by certbot
|
||||
VOLUME /etc/letsencrypt
|
||||
|
||||
# Application configuration for our site
|
||||
COPY nginx/quic.video.conf /etc/nginx/conf.d/quic.video.conf
|
||||
|
||||
# The script to init and run nginx
|
||||
COPY nginx/run.sh /run/warp-player.sh
|
||||
|
||||
# Copy over the web contents
|
||||
COPY dist/* /var/www/quic.video
|
||||
|
||||
# Run the shell script
|
||||
CMD /run/warp-player.sh
|
|
@ -0,0 +1,6 @@
|
|||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name quic.video;
|
||||
root /var/www/quic.video;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
# Try to generate a certificate that expires in 90 days.
|
||||
# This will listen on port 80 and serve a challenge file, proving we own the domain.
|
||||
certbot --nginx --email kixelated@gmail.com -d quic.video --agree-tos
|
||||
|
||||
# The certbot nginx plugin will automatically append the certs to the configuration.
|
||||
nginx
|
|
@ -0,0 +1,10 @@
|
|||
FROM golang
|
||||
|
||||
WORKDIR /usr/src/warp
|
||||
|
||||
ENV GOPRIVATE=*
|
||||
|
||||
COPY . .
|
||||
RUN go build -v -o /usr/local/bin/warp-server .
|
||||
|
||||
CMD [ "warp-server" ]
|
Loading…
Reference in New Issue