forked from aws-samples/aws-cdk-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ecs/elbv2): add example showing how to share LB across stacks
- Loading branch information
Rico Huijbers
committed
Oct 24, 2019
1 parent
8fe471d
commit e32d594
Showing
9 changed files
with
275 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
This example shows how to use a load balancer in a different | ||
stack to load balance to an ECS service. | ||
|
||
You must either create an `ApplicationListener` in the same stack as your | ||
ECS service, or create an empty `TargetGroup` in your load balancer stack | ||
and register your ECS service into that. | ||
|
||
This example demoes both of these possibilities. It uses Fargate, | ||
but the same principles hold for EC2 services. | ||
|
||
(A third option, not pictured here, is to create the shared listener | ||
with a fixed response and add a new listener rule in the service stack). | ||
|
||
Option 1: Split at listener | ||
--------------------------- | ||
|
||
Shown in `split-at-listener.ts`, create an `ApplicationLoadBalancer` | ||
in a shared stack, and an `ApplicationListener` in the service stack. | ||
|
||
|
||
Option 1: Split at target group | ||
------------------------------- | ||
|
||
Shown in `split-at-targetgroup.ts`, create an empty `TargetGroup` in the load | ||
balancer stack, and register a `Service` into it in the service stack. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"app": "node index" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import ecs = require('@aws-cdk/aws-ecs'); | ||
import ec2 = require('@aws-cdk/aws-ec2'); | ||
import { Stack, Construct, StackProps, App } from '@aws-cdk/core'; | ||
import { SplitAtListener_LoadBalancerStack, SplitAtListener_ServiceStack } from './split-at-listener'; | ||
import { SplitAtTargetGroup_LoadBalancerStack, SplitAtTargetGroup_ServiceStack } from './split-at-targetgroup'; | ||
|
||
/** | ||
* Shared infrastructure -- VPC and Cluster | ||
*/ | ||
class SharedInfraStack extends Stack { | ||
public readonly vpc: ec2.Vpc; | ||
public readonly cluster: ecs.Cluster; | ||
|
||
constructor(scope: Construct, id: string, props: StackProps = {}) { | ||
super(scope, id, props); | ||
|
||
this.vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); | ||
this.cluster = new ecs.Cluster(this, 'Cluster', { | ||
vpc: this.vpc | ||
}); | ||
} | ||
} | ||
|
||
const app = new App(); | ||
|
||
const infra = new SharedInfraStack(app, 'CrossStackLBInfra'); | ||
|
||
// Demo that splits at Listener | ||
const splitAtListenerLBStack = new SplitAtListener_LoadBalancerStack(app, 'SplitAtListener-LBStack', { | ||
vpc: infra.vpc, | ||
}); | ||
new SplitAtListener_ServiceStack(app, 'SplitAtListener-ServiceStack', { | ||
cluster: infra.cluster, | ||
vpc: infra.vpc, | ||
loadBalancer: splitAtListenerLBStack.loadBalancer | ||
}); | ||
|
||
// Demo that splits at Target Group | ||
const splitAtTargetGroupLBStack = new SplitAtTargetGroup_LoadBalancerStack(app, 'SplitAtTargetGroup-LBStack', { | ||
vpc: infra.vpc, | ||
}); | ||
new SplitAtTargetGroup_ServiceStack(app, 'SplitAtTargetGroup-ServiceStack', { | ||
cluster: infra.cluster, | ||
vpc: infra.vpc, | ||
targetGroup: splitAtTargetGroupLBStack.targetGroup | ||
}); | ||
|
||
app.synth(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "cross-stack-load-balancer", | ||
"version": "1.0.0", | ||
"description": "EC2 Service with Application Load Balancer in a different stack", | ||
"private": true, | ||
"scripts": { | ||
"build": "tsc", | ||
"watch": "tsc -w", | ||
"cdk": "cdk" | ||
}, | ||
"author": { | ||
"name": "Amazon Web Services", | ||
"url": "https://aws.amazon.com", | ||
"organization": true | ||
}, | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"@types/node": "^8.10.38", | ||
"typescript": "^3.2.4" | ||
}, | ||
"dependencies": { | ||
"@aws-cdk/aws-ec2": "*", | ||
"@aws-cdk/aws-ecs": "*", | ||
"@aws-cdk/aws-elasticloadbalancingv2": "*", | ||
"@aws-cdk/core": "*" | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
typescript/ecs/cross-stack-load-balancer/split-at-listener.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import ecs = require('@aws-cdk/aws-ecs'); | ||
import ec2 = require('@aws-cdk/aws-ec2'); | ||
import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); | ||
import { Stack, Construct, StackProps, CfnOutput } from '@aws-cdk/core'; | ||
|
||
|
||
//--------------------------------------------------------------------------- | ||
// Load balancer stack | ||
|
||
export interface SplitAtListener_LoadBalancerStackProps extends StackProps { | ||
vpc: ec2.IVpc; | ||
} | ||
|
||
export class SplitAtListener_LoadBalancerStack extends Stack { | ||
public readonly loadBalancer: elbv2.ApplicationLoadBalancer; | ||
|
||
constructor(scope: Construct, id: string, props: SplitAtListener_LoadBalancerStackProps) { | ||
super(scope, id, props); | ||
|
||
this.loadBalancer = new elbv2.ApplicationLoadBalancer(this, 'LoadBalancer', { | ||
vpc: props.vpc, | ||
internetFacing: true | ||
}); | ||
|
||
new CfnOutput(this, 'LoadBalancerDNS', { value: this.loadBalancer.loadBalancerDnsName, }); | ||
} | ||
} | ||
|
||
//--------------------------------------------------------------------------- | ||
// Service stack | ||
|
||
export interface SplitAtListener_ServiceStackProps extends StackProps { | ||
vpc: ec2.IVpc; | ||
cluster: ecs.ICluster; | ||
loadBalancer: elbv2.IApplicationLoadBalancer; | ||
} | ||
|
||
export class SplitAtListener_ServiceStack extends Stack { | ||
constructor(scope: Construct, id: string, props: SplitAtListener_ServiceStackProps) { | ||
super(scope, id, props); | ||
|
||
// Standard ECS service setup | ||
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); | ||
const container = taskDefinition.addContainer('web', { | ||
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), | ||
memoryLimitMiB: 256, | ||
}); | ||
|
||
container.addPortMappings({ | ||
containerPort: 80, | ||
protocol: ecs.Protocol.TCP | ||
}); | ||
|
||
const service = new ecs.FargateService(this, "Service", { | ||
cluster: props.cluster, | ||
taskDefinition, | ||
}); | ||
|
||
// Create a new listener in the current scope, add targets to it | ||
const listener = new elbv2.ApplicationListener(this, 'Listener', { | ||
loadBalancer: props.loadBalancer, // ! need to pass load balancer to attach to ! | ||
port: 80, | ||
}); | ||
|
||
listener.addTargets('ECS', { | ||
port: 80, | ||
targets: [service], | ||
}); | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
typescript/ecs/cross-stack-load-balancer/split-at-targetgroup.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import ecs = require('@aws-cdk/aws-ecs'); | ||
import ec2 = require('@aws-cdk/aws-ec2'); | ||
import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); | ||
import { Stack, Construct, StackProps, CfnOutput } from '@aws-cdk/core'; | ||
|
||
|
||
//--------------------------------------------------------------------------- | ||
// Load balancer stack | ||
|
||
export interface SplitAtTargetGroup_LoadBalancerStackProps extends StackProps { | ||
vpc: ec2.IVpc; | ||
} | ||
|
||
export class SplitAtTargetGroup_LoadBalancerStack extends Stack { | ||
public readonly targetGroup: elbv2.ApplicationTargetGroup; | ||
|
||
constructor(scope: Construct, id: string, props: SplitAtTargetGroup_LoadBalancerStackProps) { | ||
super(scope, id, props); | ||
|
||
const loadBalancer = new elbv2.ApplicationLoadBalancer(this, 'LoadBalancer', { | ||
vpc: props.vpc, | ||
internetFacing: true | ||
}); | ||
|
||
this.targetGroup = new elbv2.ApplicationTargetGroup(this, 'TargetGroup', { | ||
vpc: props.vpc, | ||
port: 80, | ||
}); | ||
|
||
loadBalancer.addListener('Listener', { | ||
port: 80, | ||
defaultTargetGroups: [this.targetGroup] | ||
}); | ||
|
||
new CfnOutput(this, 'LoadBalancerDNS', { value: loadBalancer.loadBalancerDnsName, }); | ||
} | ||
} | ||
|
||
//--------------------------------------------------------------------------- | ||
// Service stack | ||
|
||
export interface SplitAtTargetGroup_ServiceStackProps extends StackProps { | ||
vpc: ec2.IVpc; | ||
cluster: ecs.ICluster; | ||
|
||
// NOTE: Temporarily an ApplicationTargetGroup (instead of the corresponding interface) | ||
// because the interface does not contain addTarget() yet. Can be rectified after CDK | ||
// 1.15.0. | ||
targetGroup: elbv2.ApplicationTargetGroup; | ||
} | ||
|
||
export class SplitAtTargetGroup_ServiceStack extends Stack { | ||
constructor(scope: Construct, id: string, props: SplitAtTargetGroup_ServiceStackProps) { | ||
super(scope, id, props); | ||
|
||
// Standard ECS service setup | ||
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef'); | ||
const container = taskDefinition.addContainer('web', { | ||
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), | ||
memoryLimitMiB: 256, | ||
}); | ||
|
||
container.addPortMappings({ | ||
containerPort: 80, | ||
protocol: ecs.Protocol.TCP | ||
}); | ||
|
||
const service = new ecs.FargateService(this, "Service", { | ||
cluster: props.cluster, | ||
taskDefinition, | ||
}); | ||
|
||
// Connect service to TargetGroup | ||
// NOTE: This does not introduce a cycle because ECS Services are self-registering | ||
// (they point to the TargetGroup instead of the other way around). | ||
props.targetGroup.addTarget(service); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"compilerOptions": { | ||
"target":"ES2018", | ||
"module": "commonjs", | ||
"lib": ["es2016", "es2017.object", "es2017.string"], | ||
"strict": true, | ||
"noImplicitAny": true, | ||
"strictNullChecks": true, | ||
"noImplicitThis": true, | ||
"alwaysStrict": true, | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": false, | ||
"inlineSourceMap": true, | ||
"inlineSources": true, | ||
"experimentalDecorators": true, | ||
"strictPropertyInitialization":false | ||
} | ||
} | ||
|