From 27cc82186c73db5e68e00448133dd6e79e13d90c Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Fri, 8 Oct 2021 02:25:15 +0800 Subject: [PATCH] feat(elbv2): support ALB target for NLB (#16687) This PR allows NLB to have a single ALB as the target. Fixes: #16679 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/alb-target.ts | 45 ++ .../lib/index.ts | 1 + .../package.json | 4 +- .../test/alb-target.test.ts | 68 ++ .../test/integ.alb-target.expected.json | 673 ++++++++++++++++++ .../test/integ.alb-target.ts | 49 ++ .../aws-elasticloadbalancingv2/README.md | 41 ++ .../lib/shared/enums.ts | 5 + 8 files changed, 885 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json create mode 100644 packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts new file mode 100644 index 0000000000000..3cc67a0984a2e --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/alb-target.ts @@ -0,0 +1,45 @@ +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; + +/** + * A single Application Load Balancer as the target for load balancing. + */ +export class AlbArnTarget implements elbv2.INetworkLoadBalancerTarget { + /** + * Create a new alb target + * + * @param albArn The ARN of the application load balancer to load balance to + * @param port The port on which the target is listening + */ + constructor(private readonly albArn: string, private readonly port: number) { + } + + /** + * Register this alb target with a load balancer + * + * Don't call this, it is called automatically when you add the target to a + * load balancer. + */ + public attachToNetworkTargetGroup(targetGroup: elbv2.INetworkTargetGroup): elbv2.LoadBalancerTargetProps { + return this.attach(targetGroup); + } + + private attach(_targetGroup: elbv2.ITargetGroup): elbv2.LoadBalancerTargetProps { + return { + targetType: elbv2.TargetType.ALB, + targetJson: { id: this.albArn, port: this.port }, + }; + } +} + +/** + * A single Application Load Balancer as the target for load balancing. + */ +export class AlbTarget extends AlbArnTarget { + /** + * @param alb The application load balancer to load balance to + * @param port The port on which the target is listening + */ + constructor(alb: elbv2.ApplicationLoadBalancer, port: number) { + super(alb.loadBalancerArn, port); + } +} diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts index 145ac293c4a98..dce98a495a5d6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/lib/index.ts @@ -1,3 +1,4 @@ +export * from './alb-target'; export * from './ip-target'; export * from './instance-target'; export * from './lambda-target'; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 37f4fe6c1d5ce..e9b09e29964ff 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -70,7 +70,9 @@ "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "jest": "^26.6.3" + "jest": "^26.6.3", + "@aws-cdk/aws-ecs": "0.0.0", + "@aws-cdk/aws-ecs-patterns": "0.0.0" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts new file mode 100644 index 0000000000000..1ccea0b91d1b2 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/alb-target.test.ts @@ -0,0 +1,68 @@ +import { expect, haveResource } from '@aws-cdk/assert-internal'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import { Stack } from '@aws-cdk/core'; +import * as targets from '../lib'; + +test('Can create target groups with alb target', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); + const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc }); + const listener = nlb.addListener('Listener', { port: 80 }); + + // WHEN + listener.addTargets('Targets', { + targets: [new targets.AlbTarget(alb, 80)], + port: 80, + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'TCP', + Targets: [ + { + Id: { + Ref: 'ALBAEE750D2', + }, + Port: 80, + }, + ], + TargetType: 'alb', + VpcId: { + Ref: 'Stack8A423254', + }, + })); +}); + +test('Can create target groups with alb arn target', () => { + // GIVEN + const stack = new Stack(); + const vpc = new ec2.Vpc(stack, 'Stack'); + const nlb = new elbv2.NetworkLoadBalancer(stack, 'NLB', { vpc }); + const listener = nlb.addListener('Listener', { port: 80 }); + + // WHEN + listener.addTargets('Targets', { + targets: [new targets.AlbArnTarget('MOCK_ARN', 80)], + port: 80, + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'TCP', + Targets: [ + { + Id: 'MOCK_ARN', + Port: 80, + }, + ], + TargetType: 'alb', + VpcId: { + Ref: 'Stack8A423254', + }, + })); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json new file mode 100644 index 0000000000000..8832e3edf3726 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.expected.json @@ -0,0 +1,673 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "TestStack/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "TaskTaskRoleE98524A1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Task79114B6B": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "public.ecr.aws/nginx/nginx:latest", + "Name": "nginx", + "PortMappings": [ + { + "ContainerPort": 80, + "Protocol": "tcp" + } + ] + } + ], + "Cpu": "256", + "Family": "TestStackTask24CEEDF4", + "Memory": "512", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskTaskRoleE98524A1", + "Arn" + ] + } + } + }, + "ServiceLBE9A1ADBC": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + } + ], + "Scheme": "internal", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ], + "Type": "application" + } + }, + "ServiceLBSecurityGroupF7435A5C": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatically created Security Group for ELB TestStackServiceLBD3BB32E9", + "SecurityGroupIngress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow from anyone on port 80", + "FromPort": 80, + "IpProtocol": "tcp", + "ToPort": 80 + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ServiceLBSecurityGrouptoTestStackServiceSecurityGroup59159BDD804A6BA8AC": { + "Type": "AWS::EC2::SecurityGroupEgress", + "Properties": { + "GroupId": { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "DestinationSecurityGroupId": { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + }, + "FromPort": 80, + "ToPort": 80 + } + }, + "ServiceLBPublicListener46709EAA": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "ServiceLBPublicListenerECSGroup0CC8688C" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "ServiceLBE9A1ADBC" + }, + "Port": 80, + "Protocol": "HTTP" + } + }, + "ServiceLBPublicListenerECSGroup0CC8688C": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "Port": 80, + "Protocol": "HTTP", + "TargetType": "ip", + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "Service9571FDD8": { + "Type": "AWS::ECS::Service", + "Properties": { + "Cluster": { + "Ref": "EcsDefaultClusterMnL3mNNYNVpc18E0451A" + }, + "DeploymentConfiguration": { + "MaximumPercent": 200, + "MinimumHealthyPercent": 50 + }, + "EnableECSManagedTags": false, + "HealthCheckGracePeriodSeconds": 60, + "LaunchType": "FARGATE", + "LoadBalancers": [ + { + "ContainerName": "nginx", + "ContainerPort": 80, + "TargetGroupArn": { + "Ref": "ServiceLBPublicListenerECSGroup0CC8688C" + } + } + ], + "NetworkConfiguration": { + "AwsvpcConfiguration": { + "AssignPublicIp": "DISABLED", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + } + ], + "Subnets": [ + { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + }, + { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + ] + } + }, + "TaskDefinition": { + "Ref": "Task79114B6B" + } + }, + "DependsOn": [ + "ServiceLBPublicListenerECSGroup0CC8688C", + "ServiceLBPublicListener46709EAA" + ] + }, + "ServiceSecurityGroupEEA09B68": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "TestStack/Service/Service/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "ServiceSecurityGroupfromTestStackServiceLBSecurityGroup76260E3B8004FB511A": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Load balancer to target", + "FromPort": 80, + "GroupId": { + "Fn::GetAtt": [ + "ServiceSecurityGroupEEA09B68", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "ServiceLBSecurityGroupF7435A5C", + "GroupId" + ] + }, + "ToPort": 80 + } + }, + "EcsDefaultClusterMnL3mNNYNVpc18E0451A": { + "Type": "AWS::ECS::Cluster" + }, + "NlbBCDB97FE": { + "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Properties": { + "LoadBalancerAttributes": [ + { + "Key": "deletion_protection.enabled", + "Value": "false" + }, + { + "Key": "load_balancing.cross_zone.enabled", + "Value": "true" + } + ], + "Scheme": "internet-facing", + "Subnets": [ + { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + ], + "Type": "network" + }, + "DependsOn": [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet2DefaultRoute97F91067" + ] + }, + "NlblistenerBE297616": { + "Type": "AWS::ElasticLoadBalancingV2::Listener", + "Properties": { + "DefaultActions": [ + { + "TargetGroupArn": { + "Ref": "NlblistenerTargetsGroupDD2A3CB0" + }, + "Type": "forward" + } + ], + "LoadBalancerArn": { + "Ref": "NlbBCDB97FE" + }, + "Port": 80, + "Protocol": "TCP" + } + }, + "NlblistenerTargetsGroupDD2A3CB0": { + "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", + "Properties": { + "HealthCheckProtocol": "HTTP", + "Port": 80, + "Protocol": "TCP", + "Targets": [ + { + "Id": { + "Ref": "ServiceLBE9A1ADBC" + }, + "Port": 80 + } + ], + "TargetType": "alb", + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + } + }, + "Outputs": { + "ServiceLoadBalancerDNSEC5B149E": { + "Value": { + "Fn::GetAtt": [ + "ServiceLBE9A1ADBC", + "DNSName" + ] + } + }, + "ServiceServiceURL250C0FB6": { + "Value": { + "Fn::Join": [ + "", + [ + "http://", + { + "Fn::GetAtt": [ + "ServiceLBE9A1ADBC", + "DNSName" + ] + } + ] + ] + } + }, + "NlbEndpoint": { + "Value": { + "Fn::Join": [ + "", + [ + "http://", + { + "Fn::GetAtt": [ + "NlbBCDB97FE", + "DNSName" + ] + } + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts new file mode 100644 index 0000000000000..80a5e6880ffab --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/test/integ.alb-target.ts @@ -0,0 +1,49 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as patterns from '@aws-cdk/aws-ecs-patterns'; +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import { App, CfnOutput, Stack, StackProps } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import * as targets from '../lib'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2, natGateways: 1 }); + + const task = new ecs.FargateTaskDefinition(this, 'Task', { cpu: 256, memoryLimitMiB: 512 }); + task.addContainer('nginx', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest'), + portMappings: [{ containerPort: 80 }], + }); + const svc = new patterns.ApplicationLoadBalancedFargateService(this, 'Service', { + vpc, + taskDefinition: task, + publicLoadBalancer: false, + }); + + const nlb = new elbv2.NetworkLoadBalancer(this, 'Nlb', { + vpc, + crossZoneEnabled: true, + internetFacing: true, + }); + const listener = nlb.addListener('listener', { + port: 80, + }); + + listener.addTargets('Targets', { + targets: [new targets.AlbTarget(svc.loadBalancer, 80)], + port: 80, + healthCheck: { + protocol: elbv2.Protocol.HTTP, + }, + }); + + new CfnOutput(this, 'NlbEndpoint', { value: `http://${nlb.loadBalancerDnsName}` }); + } +} + +const app = new App(); +new TestStack(app, 'TestStack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index 200322e52999e..f3d23b5e827cf 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -323,6 +323,47 @@ listener.addTargets('Targets', { Only a single Lambda function can be added to a single listener rule. +## Using Application Load Balancer Targets + +To use a single application load balancer as a target for the network load balancer, use the integration class in the +`@aws-cdk/aws-elasticloadbalancingv2-targets` package: + +```ts +import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as targets from '@aws-cdk/aws-elasticloadbalancingv2-targets'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as patterns from '@aws-cdk/aws-ecs-patterns'; + +const task = new ecs.FargateTaskDefinition(this, 'Task', { cpu: 256, memoryLimitMiB: 512 }); +task.addContainer('nginx', { + image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest'), + portMappings: [{ containerPort: 80 }], +}); + +const svc = new patterns.ApplicationLoadBalancedFargateService(this, 'Service', { + vpc, + taskDefinition: task, + publicLoadBalancer: false, +}); + +const nlb = new elbv2.NetworkLoadBalancer(this, 'Nlb', { + vpc, + crossZoneEnabled: true, + internetFacing: true, +}); + +const listener = nlb.addListener('listener', { port: 80 }); + +listener.addTargets('Targets', { + targets: [new targets.AlbTarget(svc.loadBalancer, 80)], + port: 80, +}); + +new CfnOutput(this, 'NlbEndpoint', { value: `http://${nlb.loadBalancerDnsName}`}) +``` + +Only the network load balancer is allowed to add the application load balancer as the target. + ## Configuring Health Checks Health checks are configured upon creation of a target group: diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts index a711211a44065..2dc293e1b8905 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/enums.ts @@ -170,6 +170,11 @@ export enum TargetType { * Target is a single Lambda Function */ LAMBDA = 'lambda', + + /** + * Target is a single Application Load Balancer + */ + ALB = 'alb', } /**