13

I am trying to wrap my head around how to create a reusable VPC that can be used across multiple stacks using AWS CDK. I want to be able to create different stack per project and then be able to import the VPC that should be assigned to the different stacks. I also want to create this using a good structure where I can deploy different stacks at different times (meaning: I do not want to deploy all stacks at once).

I have tried the following approach but this will create a new VPC per stack which is not what I want to achieve, instead I would like to create my VPC once and then if it already exists it will simply reuse the previous created.

app.ts

import cdk = require('@aws-cdk/core');
import { Stack1 } from '../lib/stack1';
import { Stack2 } from '../lib/stack2';

const app = new cdk.App();

new Stack1(app, "Stack1");
new Stack2(app, "Stack2");

stack1.ts

import cdk = require('@aws-cdk/core');

import { Configurator } from './configurators/configurator'

export class Stack1 extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const configurator = new Configurator(scope, "Stack1");

    // later reuse vpc from configurator using configurator.vpc
  }
}

stack2.ts

import cdk = require('@aws-cdk/core');

import { Configurator } from './configurators/configurator'

export class Stack2 extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const configurator = new Configurator(scope, "Stack2");

    // later reuse vpc from configurator using configurator.vpc
  }
}

configurator.ts

import cdk = require('@aws-cdk/core');
import ec2 = require("@aws-cdk/aws-ec2");

export class Configurator {

  vpc: ec2.Vpc;

  constructor(scope: cdk.Construct, name: string) {
    this.vpc = new ec2.Vpc(scope, "MyVPC", {
      maxAzs: 3
    });
  }
}

After doing

cdk synth
cdk deploy Stack1
cdk deploy Stack2

This will create 2 VPCs and not reusing 1 VPC as I would like. I will deploy the stacks to same account and region.

How can I change my approach in order to achieve the output I am looking for? I want to be able to deploy my stacks independently of each other.

alkesos
  • 335
  • 2
  • 8
  • Not sure if this is what you are looking for: I'm not familiar with AWS CDK but I am with CloudFormation. There you can create a stack which creates the VPC and perform an export value. In all different stacks you can do an "importValue" to import the VPC and reuse the VPC in multiple stacks. Als you can not create the stack which created the VPC as long as other stacks are using it. https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Fn.html#static-import-wbr-valuesharedvaluetoimport – lvthillo Aug 23 '19 at 11:48

2 Answers2

9

If you intend to reuse the VPC in different stacks, I'd recommend placing it in a separate stack, since your VPC stack will have a different lifecycle than your application stacks.

Here's what I'd do. I hope you don't mind a bit of Python :)

First, define your VPC in VpcStack:

class VpcStack(core.Stack):
    def __init__(self, app: core.App, id: str, **kwargs) -> None:
        super().__init__(app, id, **kwargs)
        aws_ec2.Vpc(self, 'MyVPC', max_azs=3)

Then look it up in another stack:

class Stack1(core.Stack):
    def __init__(self, app: core.App, id: str, **kwargs) -> None:
        super().__init__(app, id, **kwargs)
        # Lookup the VPC named 'MyVPC' created in stack 'vpc-stack'
        my_vpc = aws_ec2.Vpc.from_lookup(self, 'MyVPC', vpc_name=f'vpc-stack/MyVPC')
        # You can now use the VPC in ECS cluster, etc.

And this would be your cdk_app.py:

app = core.App()
vpc = VpcStack(app, 'vpc-stack')
stack1 = Stack1(app, 'stack1')
0x32e0edfb
  • 707
  • 1
  • 6
  • 18
  • 1
    I would avoid using `fromLookup` as that makes the app environment-specific. It's better to just pass a reference to the VPC object to other stacks directly, that will keep the app environment-agnostic. – gshpychka Apr 22 '21 at 13:55
9

I tried 0x32e0edfb answer and got some problem. so I fix like this.

VPC Stack

class VpcStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self.eks_vpc = ec2.Vpc(self, 'eks-vpc',
            cidr='10.1.0.0/16',
            max_azs=2
        )

share VPC to other Stack

class EksClusterStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, props: ec2.Vpc, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        cluster = eks.Cluster(self, 'eks-control-plane',
            vpc=props,
            default_capacity=0
        )

and then app.py file

app = core.App()

vpc_stack = VpcStack(app, 'vpc-stack')
eks_cluster_stack = EksClusterStack(app, 'eks-cluster', vpc_stack.eks_vpc)

eks_cluster_stack.add_dependency(vpc_stack)

app.synth()

from_lookup is much better used on already existing VPC.

so I choose to use share-vpcs to share VPC information.

from_lookup only does the API call once - then, the data is cached in the cdk.context.json file, which should be committed to source control

That problem was when I recreating the same VPC.

cdk.context.json didn't update to lasted version. So when I use from_lookup always get old vpc-id.

I need to use cdk context --clear command and then deploy again. cdk.context.json would get lasted version vpc-id.

Finally, it can work properly on from_lookup method.

ref: https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-eks/test/integ.eks-kubectl.lit.ts

https://docs.aws.amazon.com/cdk/latest/guide/context.html

RicoChen
  • 111
  • 3