How can I reference existing resources?
As you using CDK with deploy your project and sometimes it may separated into vary GitHub repo, and wondering how can I easy share VPC and Subnet within those projects and so on.
To do that, we will setup 3 different projects which name vpcStack
(VPC), LambdaStack
(Lambda with ApiGateway) and ecrStack
(docker image handled by Fargate and a Loadbalancer)
Example vpcStack
// lib/vpcStack.ts
import * as cdk from '@aws-cdk/core';
import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'
import * as ec2 from '@aws-cdk/aws-ec2'
export class SygnaVpcStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, `VPC`, {
cidr: '10.192.0.0/16',
maxAzs: 2,
natGateways: 1,
enableDnsHostnames: true,
enableDnsSupport: true,
})
const nlb = new elbv2.NetworkLoadBalancer(this, `ElB`, {
vpc:vpc,
})
new cdk.CfnOutput(this, "VPC-id", {value: vpc.vpcId });
}
}
After you deployed to AWS Cloudformation, you will get something like this vpc-05ea90e
, this will be your current VPCId
ApiStack
// lib/ApiStack.ts
const vpc = ec2.Vpc.fromLookup(this, "referenced-vpc", {
vpcId: "vpc-0axxxx0e"
});
const ElbARN =
"arn:aws:elasticloadbalancing:ap-southeast-1:9xxxxxx587:loadbalancer/net/8Mxxxx/2e0xxxxxd0";
const Elb = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(
this,
"api-gateway-elb",
{
loadBalancerArn: ElbARN,
vpc: vpc
}
);
const ApiGateway = new apigateway.VpcLink(
this,
"apigateway",
{
description: "Api Gateway build by CDK",
vpcLinkName: "api-gateway"
}
);
// Attaching Api gateway to current VPC
ApiGateway.addTargets(sygnaElb);
const api = new lambda.Function(this, "myLambda", {
runtime: lambda.Runtime.NODEJS_10_X,
code: lambda.AssetCode.fromAsset("lambda"),
handler: "index.handler",
vpc: vpc,
memorySize: 256,
timeout: cdk.Duration.seconds(30),
environment: {
NODE_ENV: environment.NODE_ENV,
}
});
api.role?.addToPolicy(
new iam.PolicyStatement({
actions: ["dynamodb:*"],
resources: [
`arn:aws:dynamodb:${environment.AWS_DYNAMO_REGION}:*:table/*`
]
})
);
api.role?.addToPolicy(
new iam.PolicyStatement({
actions: ["ssm:*"],
resources: ["*"]
})
);
ecrStack example
// lib/ecrStack.tx
const ROLE_ARN = `arn:aws:iam::${ARNID}:role/ecsTaskExecutionRole`
const dbPrefix = `${stage}_`
const jwt_secret = `arn:aws:ssm:${REGION}:${ARNID}:parameter/back-office/dev/JWT_SECRET`
const role = iam.Role.fromRoleArn(this, 'Role', ROLE_ARN)
const JWT_SECRET = sm.Secret.fromSecretAttributes(this, 'JWT_SECRET', {secretArn: jwt_secret})
const vpcNamespaceName = `bob${stage}`
const vpc = ec2.Vpc.fromLookup(this, 'referenced-vpc', {
vpcId: 'vpc-0xxx0e',
})
const vpcNamespace = new servicediscovery.PrivateDnsNamespace(
this,
'VPCNamespace',
{
name: vpcNamespaceName,
vpc,
},
)
const vpcService = vpcNamespace.createService('vpcService', {
dnsRecordType: servicediscovery.DnsRecordType.A,
dnsTtl: cdk.Duration.seconds(300),
loadBalancer: true,
})
const cluster = new ecs.Cluster(this, 'Cluster', {
vpc: vpc,
})
const GatewaytaskDef = new ecs.FargateTaskDefinition(
this,
'GatewayTaskDefinition',
{
executionRole: role,
},
)
const GatewayContainer = new ecs.ContainerDefinition(
this,
'servicegateway',
{
image: ecs.ContainerImage.fromRegistry(Gateway_IMAGE),
taskDefinition: GatewaytaskDef,
logging: new ecs.AwsLogDriver({ streamPrefix: 'GatewayContainer' }),
environment: {
DB_TABLE_PREFIX: dbPrefix,
},
secrets: {
JWT_SECRET: ecs.Secret.fromSecretsManager(JWT_SECRET),
},
},
)
GatewayContainer.addPortMappings({
hostPort: gatewayPort,
containerPort: gatewayPort,
})
const GatewayFargateService = new ecs.FargateService(
this,
'serviceGatewayFargate',
{
cluster: cluster,
taskDefinition: GatewaytaskDef,
assignPublicIp: true,
desiredCount: 2,
serviceName: 'servicegateway',
vpcSubnets: vpc.selectSubnets({
subnetType: ec2.SubnetType.PUBLIC,
}),
},
)
GatewayFargateService.connections.allowFromAnyIpv4(
ec2.Port.tcpRange(0, 65535),
'allow all port',
)
GatewayFargateService.enableCloudMap({
cloudMapNamespace: vpcNamespace,
name: 'servicegateway',
dnsRecordType: servicediscovery.DnsRecordType.A,
dnsTtl: cdk.Duration.seconds(60),
//failureThreshold: 10
})
const Gatewayscaling = GatewayFargateService.autoScaleTaskCount({
maxCapacity: 4,
minCapacity: 2,
})
Gatewayscaling.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 50,
})
const alb = new elb.ApplicationLoadBalancer(this, 'LoadBalancer', {
vpc: vpc,
internetFacing: true,
ipAddressType: elb.IpAddressType.IPV4,
vpcSubnets: vpc.selectSubnets({
subnetType: ec2.SubnetType.PUBLIC,
}),
})
vpcService.registerLoadBalancer('LoadBalancer', alb)
const tg = new elb.ApplicationTargetGroup(this, 'TargetGroup', {
protocol: elb.ApplicationProtocol.HTTP,
port: 80,
vpc: vpc,
targetType: elb.TargetType.IP,
targets: [GatewayFargateService],
healthCheck: {
interval: cdk.Duration.seconds(60),
path: '/.well-known/apollo/server-health',
timeout: cdk.Duration.seconds(5),
},
})
const listener = alb.addListener('Listener', {
protocol: elb.ApplicationProtocol.HTTP,
port: 80,
defaultTargetGroups: [tg],
})
const rule = new elb.ApplicationListenerRule(this, 'rule', {
listener,
priority: 1,
pathPattern: '*',
targetGroups: [tg],
})
new cdk.CfnOutput(this, 'ExportLoadBalancerDNS', {
value: `http://${alb.loadBalancerDnsName}/`,
})
That’s it for the demo
When you use fromLookup
function, you have to specified AWS Region where your current VPC is located. For example I use Singapore, aka ap-southeast-1
// bin/stack.ts
import { CdkStack } from '../lib/cdk-stack'
const envSingaporeDev = { account: '96000007', region: 'ap-southeast-1' }
const bob = new CdkStack(app, 'CdkStack', {env: envSingaporeDev})
While deploy, you have to do cdk synth --profile xxx-sg
to get let CDK able to get VPC id that you referencing. Final step, deploy to Cloudformation, cdk deploy --profile xxx-sg
.
Source
- https://garbe.io/blog/2019/09/20/hey-cdk-how-to-use-existing-resources/
- https://gitter.im/awslabs/aws-cdk?at=5cadf5c6a84e0c501a0a9b8a
- https://github.com/aws/aws-cdk/issues/4794
- https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts
- https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.NetworkLoadBalancer.html#static-from-wbr-network-wbr-load-wbr-balancer-wbr-attributesscope-id-attrs
- https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html
- https://stackoverflow.com/questions/59393111/cdk-split-api-gateway-stack-into-2-small-stacks