🔰
CDK のクロススタック参照での循環参照エラー
- 状況: AWS CDK で他のスタックのリソースを参照する際、参照が循環していると
Error: 'xxx' depends on 'yyy' (xxx -> yyy/...). Adding this dependency (yyy -> xxx/...) would create a cyclic reference.
というエラーが発生する。 - 対処法: スタック
xxx
内のリソースがスタックyyy
で定義されたリソースを参照している箇所を、yyy
内のリソースがxxx
で定義されたリソースを参照するように修正する。
状況
-
CommonStack
で VPC と RDS インタンスを定義する。
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;
}
}
-
props
経由で、CommonStack
からAppStack
へ VPC と RDS インスタンスを渡す。
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,
});
-
AppStack
で EC2 インタンスを定義する。 - EC2 インスタンスからのみ RDS インスタンスに接続できるように、
Connections.allowFrom
でセキュリティグループの設定を作成する(// ★
の部分)。
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)); // ★
}
}
-
cdk synth
すると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)
対処法
-
AppStack
の EC2 がCommonStack
で定義された VPC を参照し、同時にCommonStack
の RDS がAppStack
で定義された EC2 を参照する状態になっているため、循環参照が発生している。 - セキリュティグループのインバウンドルールの定義部分(
// ★
)を、EC2 が RDS を参照するように修正する。
修正前
props.db.connections.allowFrom(instance, ec2.Port.tcp(3306)); // ★
修正跡
instance.connections.allowTo(props.db, ec2.Port.tcp(3306));
Discussion