ApplicationLoadBalancer just creates a cyclic resource error in Java

0

I have a cluster with a TaskDefinition and Service in CDK. I'm trying to configure an ApplicationLoadBalancer in front of the service, but I can't use ApplicationLoadBalancedEc2Service because it doesn't expose the security group or vpc subnet configuration. So I'm trying to use ApplicationLoadBalancer. But when using that I get:

 Adding this dependency (NetworkStatck -> Solr/staging:Solr:LoadBalancer/SecurityGroup/Resource.GroupId) would create a cyclic reference

The VPC is defined in the NetworkStack and the ApplicationLoadBalancer is defined in the SolrStack. The documentation mentions something about using addListener and addTarget creating a cyclic reference issue when the network is created in a separate stack and I'd have to use the longer form when defining the resources. However, after breaking out everything it still generates the cyclic reference. From what I can tell it is a SecurityGroup that is being defined by the ApplicationLoadBalancer and not my security groups.

The problem seems to arise from the fact that in Java ApplicationListener.Builder requires loadBalancer to be set. Nevermind that addListener helper method would be called on an instance of load balancer. But in Python and others they DON'T require it be set.

Here is my code that creates the ALB:

        Ec2Service solrService = Ec2Service.Builder.create(this, appId("Solr:Service") )
                .cluster(solrCluster)
                .taskDefinition(solrTask.left)
                .vpcSubnets(getSubnetSelection(NetworkStack.STORAGE_SUBNET))
                .securityGroups(listOf(storageAccessGroup, efsMount))
                .placementConstraints(listOf(
                        PlacementConstraint.distinctInstances(),
                        PlacementConstraint.memberOf("attribute:ecs.instance-type == " + settings.getInstanceType("solr.image.type") )
                ))
                .desiredCount(3)
                .build();

        ApplicationLoadBalancer lb = ApplicationLoadBalancer.Builder.create(this, appId("Solr:LoadBalancer"))
                .vpc( getVpc() )
                .vpcSubnets(getSubnetSelection(NetworkStack.STORAGE_SUBNET))
                .internetFacing(false)
                .loadBalancerName("solr")
                .build();

        ApplicationTargetGroup target = ApplicationTargetGroup.Builder.create(this, appId("Solr:TargetGroup"))
                .vpc(getVpc())
                .targets(listOf(solrService))
                .protocol(ApplicationProtocol.HTTP)
                .port(8983)
                .healthCheck(software.amazon.awscdk.services.elasticloadbalancingv2.HealthCheck.builder()
                        .protocol(Protocol.HTTP)
                        .port("8983")
                        .path("/solr/audit/admin/ping?wt=json")
                        .interval(Duration.minutes(1))
                        .unhealthyThresholdCount(2)
                        .healthyThresholdCount(5)
                        .build())
                .build();

        ApplicationListener listener = ApplicationListener.Builder.create( this, appId("Solr:ApplicationListener") )
                .port(8983)
                .protocol(ApplicationProtocol.HTTP)
                .loadBalancer(lb)
                .defaultTargetGroups(listOf(target))
                .build();

How do I fix the cyclical reference problem?

1 Answer
0

The cyclic reference error occurs because there is a dependency loop between the stacks when creating the Application Load Balancer (ALB) and the network resources. [ 1 ] To resolve this issue, you can follow these steps:

  1. Create a separate stack for the ALB, which will contain only the ALB-related resources.
  2. Pass the necessary information from the network stack to the ALB stack using CloudFormation stack outputs (class CfnOutput (construct).
  3. In the ALB stack, import the VPC and security group from the network stack using the output values.
  4. Define the ALB in the ALB stack using the imported VPC and security group.
  5. Here's an example of how you can modify your code to implement these steps:

In your NetworkStack:

  • Export the VPC and security group

  • Export the VPC ID and security group ID

  • Import the VPC and security group

  • Create the ALB

By following this approach, you will be able to reference the VPC and security group from the NetworkStack in the SolrStack to create the Application Load Balancer successfully.

One other thing to look into would be Abstractions and escape hatches. AWS CDK also provides the capability to go up an abstraction level. If you have an L1 construct, such as Ec2Service, you can create a new L2 construct (EC2 in this case) to wrap the L1 construct.[ 2 ]

Lastly, consider the usage of the DependsOn attribute. One of the primary reasons to use the DependsOn attribute is to avoid cyclic references in your AWS CDK application. Using the attribute, you can explicitly define the order in which resources should be created or modified, even if there are dependencies between them. This helps you avoid cyclic references and ensures that your resources are provisioned correctly.

References:

[ 1 ] https://aws.amazon.com/blogs/infrastructure-and-automation/handling-circular-dependency-errors-in-aws-cloudformation/#:~:text=What%20is%20a%20circular%20dependency%3F&text=Resource%20A%20is%20dependent%20on,resource%20should%20be%20created%20first [ 2 ] https://docs.aws.amazon.com/cdk/v2/guide/cfn_layer.html#cfn_layer_cfn

answered 10 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions