In this blog post, I want to show you how to create a new CDK project for your application deployment. We will initialize a new CDK app and add some constructs, then we deploy and destroy the infrastructure using the CDK CLI.
Initializing the app
To initialize the new CDK app first of all we need to install the CDK CLI on our machine. To achieve this we have to make sure that NodeJS is set up correctly. We can then install CDK using the node package manager by calling npm install -g aws-cdk
.
For our application, we create a new and empty folder called cdk-demo
and run cdk init
inside of it. The init command needs two parts of information to successfully initialize our app. We need to tell it which language we want to use and which scaffolding template to use. As project language, we can choose from TypeScript, JavaScript, Python, Java, and .NET. As a blueprint, we have templates for applications, a complete sample application, or a template for our own CDK Construct Library.
In this example, we will use the app template using TypeScript, so we call cdk init --language=typescript app
in our folder.
Configuration of the app
After the initialization finishes, we have a folder containing a new NodeJS project. The package.json file is set up to install the needed parts of CDK and to provide some scripts for using the CDK CLI.
As you can see the CDK CLI is installed as a development dependency and the core package is installed too. To make sure you use the correct version of the CDK CLI in your following command you can use the provided NPM script by using npm run cdk -- <command>
which uses the local version of CDK instead of your global one. This also makes sure that you do not need to install CDK CLI on your CI system.
If you want to use CDK constructs in your application, and you want to do this, you need to install the corresponding packages in the dependencies section here. These packages are named @aws-cdk/aws-<service>
and exist for every AWS service with CloudFormation support and also for higher-level patterns the CDK provides. A future version of CDK will fold all these packages into one module called monocdk but this will not happen earlier than v2 of the CDK.
For your CDK dependencies, you have to make sure that all use the exact same version and you should definitely pin the version to a fixed string instead of using semver in NPM. The CDK packages are not compatible with each other in different versions, no matter if it is a major, minor or patch release.
You can achieve this by removing the ^
character in front of the version. To prevent other versions from being installed, I recommend adding new dependencies by duplication a line in this file instead of using npm install --save <package>
.
For convenience, we can also add additional commands to the scripts section of the package.json
file. By adding scripts for deployment, showing diffs, and removing the stacks, we do not need to memorize the commands later on. So our new scripts section should look like this:
"scripts": {
"test": "jest",
"cdk": "cdk",
"diff": "cdk diff CdkDemoStack",
"deploy": "cdk deploy CdkDemoStack",
"destroy": "cdk destroy CdkDemoStack"
},
Folder structure
The CDK initialization created three subfolders in your project. The bin/
folder contains your CDK application definition, the lib/
folder contains your stacks and constructs, and the tst/
folder is the place to store your unit tests for your code.
Adding constructs
At first, we will have a look at the definition of our stack and add some constructs to it. We want to add an SNS topic, so we need to add the service dependency to our package.json
file.
"dependencies": {
"@aws-cdk/core": "1.54.0",
"@aws-cdk/aws-sns": "1.54.0",
"source-map-support": "^0.5.16"
}
In our lib/cdk-demo-stack.ts
file we can then create our stack. But let's look at this file first.
import * as cdk from '@aws-cdk/core';
export class CdkDemoStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
}
}
At the top, we import the CDK library for later use. Here we need to add all the additional libraries we want to use. We then export a class representing our stack that extends the CDK Stack class. The constructor of a stack and nearly all other CDK constructs follows this pattern:
- scope argument defining the location of this construct in the hierarchy tree.
- scope-unique id of the construct to identity it. This will be part of the logical name in CloudFormation later.
- class-specific properties object with additional settings.
For our stack class, we will just forward these arguments to the inherited constructor. We can then define our nested element inside this method.
We can now import the SNS library at the top of the file and then instantiate a new object of the imported class Topic. The resulting file looks like this:
import * as cdk from '@aws-cdk/core';
import * as sns from '@aws-cdk/aws-sns';
export class CdkDemoStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new sns.Topic(this, 'MyTopic', {
displayName: 'MySuperTopic',
});
}
}
Deploy the infrastructure
We are now almost ready to deploy our infrastructure into our AWS account. Let's have a look at our application configuration.
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { CdkDemoStack } from '../lib/cdk-demo-stack';
const app = new cdk.App();
new CdkDemoStack(app, 'CdkDemoStack');
This file tells CDK to create a new application that consists of one stack named CdkDemoStack
that uses our export class as the definition. To make sure that we are deploying the code into the correct AWS account and to be prepared for advanced features like resource lookups and cross-account deployments, we should pin the stack instance to a concrete AWS account and region. We do this by configuring the env
parameter of our stack properties.
new CdkDemoStack(app, 'CdkDemoStack', {
env: {
account: '123456789012', // Replace with your account id
region: 'eu-central-1',
},
});
By running npm run cdk -- synth
we can now generate our CloudFormation template based on our stack definition. The resulting template is written to the cdk.out
folder.
{
"Resources": {
"MyTopic86869434": {
"Type": "AWS::SNS::Topic",
"Properties": {
"DisplayName": "MySuperTopic"
},
"Metadata": {
"aws:cdk:path": "CdkDemoStack/MyTopic/Resource"
}
}
}
}
Using the commands in our scripts
section of the project configuration we can then deploy this stack into our AWS account.
To clean up, the stack we can run the destroy command, and CDK and CloudFormation will remove all created resources.
Conclusion
In this demo, we initialized a new CDK app using cdk init
and added an SNS topic. We then synthesized, deployed, and destroyed the infrastructure using the CDK CLI and CloudFormation.
One of the most important things to remember is the pinning of versions inside your package.json
file as mixed versions of CDK libraries lead to a lot of issues that are hard to debug.
Top comments (1)
I wondered what is CDK. Then I realized it is AWS CDK.