The AWS CDK for software-defined deployments
Dreaming of Clouds
AWS CDK
Getting started with the CDK is pretty simple. In this article, I make a few assumptions:
- You have some familiarity with AWS – enough to install, set up, and understand how to use its CLI.
- You have used a tool like CloudFormation or Terraform (or maybe the SDK or CLI) before.
- You have some programming background and are comfortable with language tool chains (e.g., Node.js npm [16] and Yarn [17]). During the rest of this article, I use TypeScript [18] as the CDK language and leverage Node.js ecosystem utilities.
Assuming you have an up-to-date node
and npm
installed, installing the AWS CDK base libraries is as simple as
$ npm install -g aws-cdk
which installs the CDK Node.js libraries. With Node set up accordingly, it places the cdk
executable in your $PATH
, allowing you to run cdk
commands from your command line. If you are curious to explore the multitude of subcommands and options now available, type cdk help
. Alternatively, you can head over to the GitHub pages [19] set up by AWS for documentation.
The CDK makes starting a new project a cinch. To begin, I'll create a new project called hello-cdk
in three simple steps from the terminal:
$ mkdir hello-cdk $ cd hello-cdk $ cdk init app --language=typescript
These commands create a new local directory named hello-cdk
, descends into that directory, and then asks the CDK to create a new application there. The CDK looks at the name of the directory it is run from with the init
command and uses that as the name of the app before setting up the base files and directories you need to get started and initializing a Git repo in the directory. In the end, you can see in Listing 1 what resides in your hello-cdk
directory after the init
.
Listing 1
Project Root Directory
drwxr-xr-x - bradmatic 8 Jan 23:52 . drwxr-xr-x - bradmatic 8 Jan 23:52 |---- bin .rw-r--r-- 194 bradmatic 8 Jan 23:52 | |---- hello-cdk.ts .rw-r--r-- 37 bradmatic 8 Jan 23:52 |---- cdk.json drwxr-xr-x - bradmatic 8 Jan 23:52 |---- lib .rw-r--r-- 246 bradmatic 8 Jan 23:52 | |---- hello-cdk-stack.ts drwxr-xr-x - bradmatic 8 Jan 23:52 |---- node_modules drwxr-xr-x - bradmatic 8 Jan 23:52 | |---- @aws-cdk drwxr-xr-x - bradmatic 8 Jan 23:52 | |---- @types ... | |---- ... drwxr-xr-x - bradmatic 8 Jan 23:52 | |---- zip-stream .rw-r--r-- 79k bradmatic 8 Jan 23:52 |---- package-lock.json .rw-r--r-- 345 bradmatic 8 Jan 23:52 |---- package.json .rw-r--r-- 320 bradmatic 20 Dec 2018 |---- README.md .rw-r--r-- 558 bradmatic 20 Dec 2018 |---- tsconfig.json
With many subdirectories under node_modules
, I truncated the output. Primarily, I'll be focusing on the contents of the bin
and lib
directories.
What's in the Box?
The CDK just created a ton of files, so I'll unpack things a bit. First, the node_modules
folder contains dependent libraries, plain and simple. As well, you will see quite a few config files. For right now, focus on the bin
and lib
directories and their contents. Listing 2 shows the content of bin/hello-cdk.ts
.
Listing 2
bin/hello-cdk.ts
#!/usr/bin/env node import cdk = require('@aws-cdk/cdk'); import { HelloCdkStack } from '../lib/hello-cdk-stack'; const app = new cdk.App(); new HelloCdkStack(app, 'HelloCdkStack'); app.run();
The import
lines import the base CDK library and a stack-specific file from lib
. Next, you define a new CDK app and instantiate a new instance of HelloCdkStack
.
Listing 3 shows lib/hello-cdk-stack.ts
, which has a clearly defined point to hook into the framework and define your resources. Although you could just throw code into this file and define resources, it's worthwhile to sit back, pause, and think about a few things before you do so – namely, reusability and modularity. I'll address these concerns individually.
Listing 3
lib/hello-cdk-stack.ts
import cdk = require('@aws-cdk/cdk'); export class HelloCdkStack extends cdk.Stack { constructor(parent: cdk.App, name: string, props?: cdk.StackProps) { super(parent, name, props); // The code that defines your stack goes here } }
Reusability
Imagine that you are tasked with defining the entire stack for the application, from the base network infrastructure up, with whatever method you use to define your deployment (in this case, the CDK). In the case of AWS, that means you will very likely start with a virtual private cloud (VPC), subnets, security groups, route tables, route table associations, network address translation (NAT) gateway(s), and so on – just for networking.
A somewhat common pattern in most organizations when starting from scratch is to reuse a single VPC to host multiple applications (oftentimes grouped by type of environment, e.g., development, QA, test, production, etc.). In light of this, bundling the base networking infrastructure together with the application stack would greatly limit the possibility of reuse and means it would not be possible to deploy a new instance of the application – perhaps for development or testing purposes – apart from its backing resources. This arrangement also bears cost implications, because resources such as NAT gateways (and perhaps other necessary infrastructure elements) incur cost the moment they are provisioned.
Your first takeaway to keep in mind as you structure your code, then, is that you'd like somehow to keep shared resources separate from the resources that are specific to your application so that those shared resources aren't coupled to instances of your application stack.
Buy this article as PDF
(incl. VAT)