Implementing a Deployment solution for AWS #152
@@ -0,0 +1,11 @@
|
|||||||
|
*.js
|
||||||
|
!jest.config.js
|
||||||
|
*.d.ts
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# CDK asset staging directory
|
||||||
|
.cdk.staging
|
||||||
|
cdk.out
|
||||||
|
|
||||||
|
# Parcel default cache directory
|
||||||
|
.parcel-cache
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
*.ts
|
||||||
|
!*.d.ts
|
||||||
|
|
||||||
|
# CDK asset staging directory
|
||||||
|
.cdk.staging
|
||||||
|
cdk.out
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# This is the deployment Infrastructure as code for use with AWS
|
||||||
|
|
||||||
|
## configuration, please set them as env var
|
||||||
|
* `LOCALTUNNEL_BASE_DOMAIN` the root domain in route53
|
||||||
|
* `LOCALTUNNEL_ROUTE53_ID` the ID of the route53 hosted zone for the domain
|
||||||
|
* `LOCALTUNNEL_DOMAIN` the domain of the localtunnel server
|
||||||
|
## After setting the environment variables, simply run:
|
||||||
|
```npm i && cdk deploy```
|
||||||
|
|
||||||
|
## Deployed Architecture
|
||||||
|
1. This Architecture brings up a ECS fargate cluster and 2 public subnets
|
||||||
|
|
||||||
|
2. It spins up a container that runs using fargate runtype with the upstream docker image
|
||||||
|
|
||||||
|
3. the container image is placed in one of the two private subnets
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import 'source-map-support/register';
|
||||||
|
import * as cdk from '@aws-cdk/core';
|
||||||
|
import { DeployStack } from '../lib/deploy-stack';
|
||||||
|
|
||||||
|
let app = new cdk.App();
|
||||||
|
// replace them with HostedZoneID in route53, the domain name for the localtunnel, and the hosted zone domain
|
||||||
|
new DeployStack(app, 'DeployStack', process.env.LOCALTUNNEL_ROUTE53_ID as string , process.env.LOCALTUNNEL_BASE_DOMAIN as string, process.env.LOCALTUNNEL_DOMAIN as string);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"app": "npx ts-node --prefer-ts-exts bin/deploy.ts",
|
||||||
|
"context": {
|
||||||
|
"@aws-cdk/core:enableStackNameDuplicates": "true",
|
||||||
|
"aws-cdk:enableDiffNoFail": "true",
|
||||||
|
"@aws-cdk/core:stackRelativeExports": "true",
|
||||||
|
"@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
roots: ['<rootDir>/test'],
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.tsx?$': 'ts-jest'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import * as cdk from '@aws-cdk/core';
|
||||||
|
|
||||||
|
// import dependencies for ECS and building a VPC
|
||||||
|
import * as ec2 from "@aws-cdk/aws-ec2";
|
||||||
|
import * as ecs from "@aws-cdk/aws-ecs";
|
||||||
|
import * as ecs_patterns from "@aws-cdk/aws-ecs-patterns";
|
||||||
|
|
||||||
|
// tls certificate with ACM
|
||||||
|
import * as route53 from '@aws-cdk/aws-route53';
|
||||||
|
import * as acm from '@aws-cdk/aws-certificatemanager';
|
||||||
|
import { FargateTaskDefinition } from '@aws-cdk/aws-ecs';
|
||||||
|
export class DeployStack extends cdk.Stack {
|
||||||
|
constructor(scope: cdk.Construct, id: string, hostedZoneID: string, zoneName: string, domainName: string, props?: cdk.StackProps) {
|
||||||
|
super(scope, id, props);
|
||||||
|
// create vpc with 3 subnets
|
||||||
|
const vpc = new ec2.Vpc(this, "LocalTunnelVPC", {
|
||||||
|
maxAzs: 3,
|
||||||
|
natGateways: 0
|
||||||
|
})
|
||||||
|
// create the ecs cluster
|
||||||
|
const cluster = new ecs.Cluster(this, "LocalTunnelCluster", {
|
||||||
|
vpc: vpc
|
||||||
|
})
|
||||||
|
// create acm cert
|
||||||
|
const DNSZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
|
||||||
|
zoneName: domainName,
|
||||||
|
hostedZoneId: hostedZoneID
|
||||||
|
})
|
||||||
|
// add wildcard CNAME
|
||||||
|
new route53.CnameRecord(this, 'CnameRecordWildcard', {
|
||||||
|
zone: DNSZone,
|
||||||
|
recordName: "*",
|
||||||
|
domainName: domainName
|
||||||
|
})
|
||||||
|
const cert = new acm.Certificate(this, 'Cert', {
|
||||||
|
domainName: domainName,
|
||||||
|
subjectAlternativeNames: ["*."+domainName],
|
||||||
|
validation: acm.CertificateValidation.fromDns(DNSZone)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// task definition
|
||||||
|
let FgTask = new FargateTaskDefinition(this, "LocaltunnelDefinition", {
|
||||||
|
cpu: 256,
|
||||||
|
memoryLimitMiB: 512,
|
||||||
|
})
|
||||||
|
FgTask.addContainer("localtunnel", {
|
||||||
|
image: ecs.ContainerImage.fromRegistry("defunctzombie/localtunnel-server:latest"),
|
||||||
|
cpu: 128,
|
||||||
|
entryPoint: ["node", "-r", "esm", "./bin/server", "--domain", domainName],
|
||||||
|
|
||||||
|
}).addPortMappings({
|
||||||
|
containerPort: 80
|
||||||
|
})
|
||||||
|
|
||||||
|
// create LBed Fargate service
|
||||||
|
let localtunnelsvc = new ecs_patterns.ApplicationLoadBalancedFargateService(this, "LocalTunnelService", {
|
||||||
|
cluster: cluster,
|
||||||
|
cpu: 512,
|
||||||
|
desiredCount: 1,
|
||||||
|
taskDefinition: FgTask,
|
||||||
|
memoryLimitMiB: 2048,
|
||||||
|
publicLoadBalancer: true,
|
||||||
|
certificate: cert,
|
||||||
|
redirectHTTP: true,
|
||||||
|
recordType: ecs_patterns.ApplicationLoadBalancedServiceRecordType.ALIAS,
|
||||||
|
listenerPort: 443,
|
||||||
|
domainName: domainName,
|
||||||
|
domainZone: DNSZone,
|
||||||
|
assignPublicIp: true
|
||||||
|
})
|
||||||
|
// set health route
|
||||||
|
localtunnelsvc.targetGroup.configureHealthCheck({
|
||||||
|
path: "/api/status"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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": {
|
||||||
|
"@aws-cdk/assert": "1.75.0",
|
||||||
|
"@types/jest": "^26.0.10",
|
||||||
|
"@types/node": "10.17.27",
|
||||||
|
"jest": "^26.4.2",
|
||||||
|
"ts-jest": "^26.2.0",
|
||||||
|
"aws-cdk": "1.75.0",
|
||||||
|
"ts-node": "^9.0.0",
|
||||||
|
"typescript": "~3.9.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@aws-cdk/aws-certificatemanager": "^1.91.0",
|
||||||
|
"@aws-cdk/aws-ec2": "^1.91.0",
|
||||||
|
"@aws-cdk/aws-ecs": "^1.91.0",
|
||||||
|
"@aws-cdk/aws-ecs-patterns": "^1.91.0",
|
||||||
|
"@aws-cdk/aws-route53": "^1.91.0",
|
||||||
|
"@aws-cdk/core": "1.75.0",
|
||||||
|
"source-map-support": "^0.5.16"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { expect as expectCDK, matchTemplate, MatchStyle } from '@aws-cdk/assert';
|
||||||
|
import * as cdk from '@aws-cdk/core';
|
||||||
|
import * as Deploy from '../lib/deploy-stack';
|
||||||
|
|
||||||
|
test('Empty Stack', () => {
|
||||||
|
const app = new cdk.App();
|
||||||
|
// WHEN
|
||||||
|
const stack = new Deploy.DeployStack(app, 'MyTestStack');
|
||||||
|
// THEN
|
||||||
|
expectCDK(stack).to(matchTemplate({
|
||||||
|
"Resources": {}
|
||||||
|
}, MatchStyle.EXACT))
|
||||||
|
});
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2018",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": ["es2018"],
|
||||||
|
"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": ["cdk.out"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user