iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔰
Cyclic Reference Errors in CDK Cross-Stack References
- Situation: When referencing resources from another stack in AWS CDK, if there is a circular reference, an error occurs:
Error: 'xxx' depends on 'yyy' (xxx -> yyy/...). Adding this dependency (yyy -> xxx/...) would create a cyclic reference. - Solution: Modify the part where a resource in stack
xxxreferences a resource defined in stackyyyso that the resource inyyyreferences the resource defined inxxxinstead.
Situation
- Define a VPC and an RDS instance in
CommonStack.
lib/common-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';
export class CommonStack extends cdk.Stack {
public vpc: ec2.Vpc;
public db: rds.DatabaseInstance;
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'Vpc', {
maxAzs: 1,
subnetConfiguration: [
{
name: 'public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
name: 'private-isolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});
const db = new rds.DatabaseInstance(this, 'Db', {
engine: rds.DatabaseInstanceEngine.MYSQL,
vpc: vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
});
this.vpc = vpc;
this.db = db;
}
}
- Pass the VPC and RDS instances from
CommonStacktoAppStackviaprops.
bin/cdk.ts
import * as cdk from 'aws-cdk-lib';
import { CommonStack } from '../lib/common-stack';
import { AppStack } from '../lib/app-stack';
const cdkApp = new cdk.App();
const commonStack = new CommonStack(cdkApp, 'CommonStack');
const appStack = new AppStack(cdkApp, 'AppStack', {
vpc: commonStack.vpc,
db: commonStack.db,
});
- Define an EC2 instance in
AppStack. - To ensure only the EC2 instance can connect to the RDS instance, create security group settings using
Connections.allowFrom(the// ★part).
lib/app-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';
interface AppStackProps extends cdk.StackProps {
vpc: ec2.Vpc;
db: rds.DatabaseInstance;
};
export class AppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: AppStackProps) {
super(scope, id, props);
const instance = new ec2.Instance(this, 'Instance', {
vpc: props.vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.NANO),
machineImage: ec2.MachineImage.latestAmazonLinux(),
});
props.db.connections.allowFrom(instance, ec2.Port.tcp(3306)); // ★
}
}
- Running
cdk synthresults in the error:Error: 'xxx' depends on 'yyy' (xxx -> yyy/...). Adding this dependency (yyy -> xxx/...) would create a cyclic reference.
node ➜ /workspace $ npx cdk synth
/workspace/node_modules/aws-cdk-lib/core/lib/stack.ts:908
throw new Error(`'${target.node.path}' depends on '${this.node.path}' (${cycleDescription}). Adding this dependency (${reason.description}) would create a cyclic reference.`);
^
Error: 'CommonStack' depends on 'AppStack' (CommonStack -> AppStack/AppInstance/InstanceSecurityGroup/Resource.GroupId). Adding this dependency (AppStack -> CommonStack/Vpc/Resource.Ref) would create a cyclic reference.
at AppStack._addAssemblyDependency (/workspace/node_modules/aws-cdk-lib/core/lib/stack.ts:908:13)
at operateOnDependency (/workspace/node_modules/aws-cdk-lib/core/lib/deps.ts:90:24)
at addDependency (/workspace/node_modules/aws-cdk-lib/core/lib/deps.ts:26:3)
at AppStack.addDependency (/workspace/node_modules/aws-cdk-lib/core/lib/stack.ts:615:18)
at resolveValue (/workspace/node_modules/aws-cdk-lib/core/lib/private/refs.ts:130:12)
at resolveReferences (/workspace/node_modules/aws-cdk-lib/core/lib/private/refs.ts:34:24)
at prepareApp (/workspace/node_modules/aws-cdk-lib/core/lib/private/prepare-app.ts:30:20)
at synthesize (/workspace/node_modules/aws-cdk-lib/core/lib/private/synthesis.ts:45:13)
at App.synth (/workspace/node_modules/aws-cdk-lib/core/lib/stage.ts:217:33)
at process.<anonymous> (/workspace/node_modules/aws-cdk-lib/core/lib/app.ts:195:45)
Solution
- A circular reference occurs because the EC2 in
AppStackreferences the VPC defined inCommonStack, while simultaneously the RDS inCommonStackreferences the EC2 defined inAppStack. - Modify the inbound rule definition for the security group (
// ★) so that the EC2 references the RDS instead.
Before fix
props.db.connections.allowFrom(instance, ec2.Port.tcp(3306)); // ★
After fix
instance.connections.allowTo(props.db, ec2.Port.tcp(3306));
Discussion