Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
image: ecs.ContainerImage.fromRegistry('nathanpeck/greeting'),
memoryLimitMiB: 128
});
greetingContainer.addPortMappings({
containerPort: 3000
});
const greetingService = new ecs.Ec2Service(this, 'greeting-service', {
cluster: cluster,
desiredCount: 2,
taskDefinition: greetingTaskDefinition
});
// Internal load balancer for the backend services
const internalLB = new elbv2.ApplicationLoadBalancer(this, 'internal', {
vpc: vpc,
internetFacing: false
});
const internalListener = internalLB.addListener('PublicListener', { port: 80, open: true });
internalListener.addTargetGroups('default', {
targetGroups: [new elbv2.ApplicationTargetGroup(this, 'default', {
vpc: vpc,
protocol: 'HTTP',
port: 80
})]
});
internalListener.addTargets('name', {
port: 80,
NAME_URL: 'http://' + internalLB.loadBalancerDnsName + '/name'
}
});
greeterContainer.addPortMappings({
containerPort: 3000
});
const greeterService = new ecs.Ec2Service(this, 'greeter-service', {
cluster: cluster,
desiredCount: 2,
taskDefinition: greeterTaskDefinition
});
// Internet facing load balancer for the frontend services
const externalLB = new elbv2.ApplicationLoadBalancer(this, 'external', {
vpc: vpc,
internetFacing: true
});
const externalListener = externalLB.addListener('PublicListener', { port: 80, open: true });
externalListener.addTargets('greeter', {
port: 80,
targets: [greeterService]
});
this.internalDNS = new cdk.CfnOutput(this, 'InternalDNS', {
exportName: 'greeter-app-internal',
value: internalLB.loadBalancerDnsName
});
this.externalDNS = new cdk.CfnOutput(this, 'ExternalDNS', {
constructor(parent: cdk.App, name: string, props: TriviaBackendStackProps) {
super(parent, name, props);
// Network infrastructure
const vpc = new Vpc(this, 'VPC', { maxAzs: 2 });
const serviceSG = new SecurityGroup(this, 'ServiceSecurityGroup', { vpc });
// Lookup pre-existing TLS certificate
const certificateArn = StringParameter.fromStringParameterAttributes(this, 'CertArnParameter', {
parameterName: 'CertificateArn-' + props.domainName
}).stringValue;
// Load balancer
const loadBalancer = new ApplicationLoadBalancer(this, 'ServiceLB', {
vpc,
internetFacing: true
});
serviceSG.connections.allowFrom(loadBalancer, Port.tcp(80));
const domainZone = HostedZone.fromLookup(this, 'Zone', { domainName: props.domainZone });
new ARecord(this, "DNS", {
zone: domainZone,
recordName: props.domainName,
target: AddressRecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)),
});
// Primary traffic listener
const listener = loadBalancer.addListener('PublicListener', {
port: 443,
open: true,
zone: domainZone,
recordName: props.domainName,
target: AddressRecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)),
});
// Primary traffic listener
const listener = loadBalancer.addListener('PublicListener', {
port: 443,
open: true,
certificateArns: [certificateArn]
});
// Second listener for test traffic
let testListener = loadBalancer.addListener('TestListener', {
port: 9002, // port for testing
protocol: ApplicationProtocol.HTTPS,
open: true,
certificateArns: [certificateArn]
});
// First target group for blue fleet
const tg1 = listener.addTargets('ECS', {
port: 80,
targets: [ // empty to begin with
new (class EmptyIpTarget implements IApplicationLoadBalancerTarget {
attachToApplicationTargetGroup(_: ApplicationTargetGroup): LoadBalancerTargetProps {
return { targetType: TargetType.IP };
}
})()
],
deregistrationDelay: cdk.Duration.seconds(30),
healthCheck: {
new Alarm(this, 'TargetGroup5xx', {
metric: tg1.metricHttpCodeTarget(HttpCodeTarget.TARGET_5XX_COUNT),
threshold: 1,
evaluationPeriods: 1,
period: cdk.Duration.minutes(1)
});
new Alarm(this, 'TargetGroup2UnhealthyHosts', {
metric: tg2.metricUnhealthyHostCount(),
threshold: 1,
evaluationPeriods: 2,
});
new Alarm(this, 'TargetGroup25xx', {
metric: tg2.metricHttpCodeTarget(HttpCodeTarget.TARGET_5XX_COUNT),
threshold: 1,
evaluationPeriods: 1,
period: cdk.Duration.minutes(1)
});
// Roles
new Role(this, 'ServiceTaskDefExecutionRole', {
assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'),
managedPolicies: [ ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy') ]
});
new Role(this, 'ServiceTaskDefTaskRole', {
assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'),
});
new Role(this, 'CodeDeployRole', {
healthyHttpCodes: '200',
healthyThresholdCount: 2,
unhealthyThresholdCount: 3,
timeout: cdk.Duration.seconds(4)
}
});
// Alarms: monitor 500s and unhealthy hosts on target groups
new Alarm(this, 'TargetGroupUnhealthyHosts', {
metric: tg1.metricUnhealthyHostCount(),
threshold: 1,
evaluationPeriods: 2,
});
new Alarm(this, 'TargetGroup5xx', {
metric: tg1.metricHttpCodeTarget(HttpCodeTarget.TARGET_5XX_COUNT),
threshold: 1,
evaluationPeriods: 1,
period: cdk.Duration.minutes(1)
});
new Alarm(this, 'TargetGroup2UnhealthyHosts', {
metric: tg2.metricUnhealthyHostCount(),
threshold: 1,
evaluationPeriods: 2,
});
new Alarm(this, 'TargetGroup25xx', {
metric: tg2.metricHttpCodeTarget(HttpCodeTarget.TARGET_5XX_COUNT),
threshold: 1,
evaluationPeriods: 1,
period: cdk.Duration.minutes(1)
const greetingService = new ecs.Ec2Service(this, 'greeting-service', {
cluster: cluster,
desiredCount: 2,
taskDefinition: greetingTaskDefinition
});
// Internal load balancer for the backend services
const internalLB = new elbv2.ApplicationLoadBalancer(this, 'internal', {
vpc: vpc,
internetFacing: false
});
const internalListener = internalLB.addListener('PublicListener', { port: 80, open: true });
internalListener.addTargetGroups('default', {
targetGroups: [new elbv2.ApplicationTargetGroup(this, 'default', {
vpc: vpc,
protocol: 'HTTP',
port: 80
})]
});
internalListener.addTargets('name', {
port: 80,
pathPattern: '/name*',
priority: 1,
targets: [nameService]
});
internalListener.addTargets('greeting', {
port: 80,
pathPattern: '/greeting*',
if (props.cluster && props.vpc) {
throw new Error('You can only specify either vpc or cluster. Alternatively, you can leave both blank');
}
this.cluster = props.cluster || this.getDefaultCluster(this, props.vpc);
this.desiredCount = props.desiredCount || 1;
const internetFacing = props.publicLoadBalancer !== undefined ? props.publicLoadBalancer : true;
const lbProps = {
vpc: this.cluster.vpc,
internetFacing
};
this.loadBalancer = props.loadBalancer !== undefined ? props.loadBalancer : new ApplicationLoadBalancer(this, 'LB', lbProps);
const targetProps = {
port: 80
};
if (props.certificate !== undefined && props.protocol !== undefined && props.protocol !== ApplicationProtocol.HTTPS) {
throw new Error('The HTTPS protocol must be used when a certificate is given');
}
const protocol = props.protocol !== undefined ? props.protocol : (props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP);
this.listener = this.loadBalancer.addListener('PublicListener', {
protocol,
open: true
});
this.targetGroup = this.listener.addTargets('ECS', targetProps);
const targetProps = {
port: 80
};
if (props.certificate !== undefined && props.protocol !== undefined && props.protocol !== ApplicationProtocol.HTTPS) {
throw new Error('The HTTPS protocol must be used when a certificate is given');
}
const protocol = props.protocol !== undefined ? props.protocol : (props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP);
this.listener = this.loadBalancer.addListener('PublicListener', {
protocol,
open: true
});
this.targetGroup = this.listener.addTargets('ECS', targetProps);
if (protocol === ApplicationProtocol.HTTPS) {
if (typeof props.domainName === 'undefined' || typeof props.domainZone === 'undefined') {
throw new Error('A domain name and zone is required when using the HTTPS protocol');
}
if (props.certificate !== undefined) {
this.certificate = props.certificate;
} else {
this.certificate = new DnsValidatedCertificate(this, 'Certificate', {
domainName: props.domainName,
hostedZone: props.domainZone
});
}
}
if (this.certificate !== undefined) {
this.listener.addCertificateArns('Arns', [this.certificate.certificateArn]);
}
const lbProps = {
vpc: this.cluster.vpc,
internetFacing
};
this.loadBalancer = props.loadBalancer !== undefined ? props.loadBalancer : new ApplicationLoadBalancer(this, 'LB', lbProps);
const targetProps = {
port: 80
};
if (props.certificate !== undefined && props.protocol !== undefined && props.protocol !== ApplicationProtocol.HTTPS) {
throw new Error('The HTTPS protocol must be used when a certificate is given');
}
const protocol = props.protocol !== undefined ? props.protocol : (props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP);
this.listener = this.loadBalancer.addListener('PublicListener', {
protocol,
open: true
});
this.targetGroup = this.listener.addTargets('ECS', targetProps);
if (protocol === ApplicationProtocol.HTTPS) {
if (typeof props.domainName === 'undefined' || typeof props.domainZone === 'undefined') {
throw new Error('A domain name and zone is required when using the HTTPS protocol');
}
if (props.certificate !== undefined) {
this.certificate = props.certificate;
} else {
this.certificate = new DnsValidatedCertificate(this, 'Certificate', {