How does AWS CDK work - Complete Guide


Borislav Hadzhiev

Last updated: Apr 13, 2022


Photo from Unsplash

Table of Contents #

  1. How AWS CDK works - Introduction
  2. Step by Step - Lifecycle of a CDK Application
  3. Conclusion

How AWS CDK works - Introduction #

CDK (Cloud Development Kit) is a service that allows us to provision AWS resources, while writing code using a programming language (TypeScript, JavaScript, Python, Java, C#).

AWS CDK takes the code we write and compiles it down to CloudFormation, before the stack is deployed.

CloudFormation is another AWS service used to provision infrastructure, however, it is written using a configuration language (YAML or JSON). CDK is the next logical level of abstraction.

CDK is easier for humans to write, read, understand and build reusable Cloud Components (Constructs) on top of.

In this article we'll go step by step and see this process from CDK stack definition to CloudFormation stack deployment.

Step by Step - Lifecycle of a CDK Application #

We'll create a small CDK application, consisting of a single Lambda function.

Then we'll follow the steps necessary for our CDK application to end up as a deployed CloudFormation stack.

The code for this article is available on GitHub

Let's create the infrastructure.

import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; // 👇 defining our CDK Stack export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const myFunction = new lambda.Function(this, 'my-function', { runtime: lambda.Runtime.NODEJS_14_X, memorySize: 1024, timeout: cdk.Duration.seconds(5), handler: 'index.main', code: lambda.Code.fromAsset(path.join(__dirname, '/../src/my-function')), }); } } // 👇 Creating our CDK App const app = new cdk.App(); // 👇 Creating our CDK Stack const myStack = new MyCdkStack(app, 'my-cdk-stack', { stackName: `my-cdk-stack`, env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });

In our code we created a single Lambda function pointing to a local file - src/my-function/index.js with a handler function called main.

The function's code can be as simple as:

async function main(event) { return {body: JSON.stringify({message: 'SUCCESS'}), statusCode: 200}; } module.exports = {main};

We issue CDK commands with the help of the CDK CLI.

In order to tell the CDK CLI how to run our CDK Code, we need a cdk.json file in the root directory of our project.

The file has an app property that is specific to the programming language we're using. This command takes care of compiling our code if necessary:

{ "app": "npx ts-node --prefer-ts-exts infra/app.ts", }

Now that we know that we are able to use the CDK CLI, we'll run the bootstrap command to provision:

  • an S3 bucket for storing asset files (code for our lambda, the CloudFormation template, etc)
  • IAM roles that grant permissions necessary for deployment
npx aws-cdk bootstrap

The next step is to synthesize our CDK application into a CloudFormation stack.

npx aws-cdk synth

This will create the cdk.out directory in our project.

Some of the files included in cdk.out are:

  • a CloudFormation template equivalent to our CDK stack
  • the code for our Lambda function
  • other assets and meta data

In our project the cdk.out directory looks like this:

cdk out directory

Since the default CloudFormation template is in json, which is hard to read, let's generate a yaml one and look at some of the details:

npx aws-cdk synth --no-staging > template.yaml

We have redirected the output of the synth command into a template.yaml file.

If we look at our lambda function we see the Metadata property:

Resources: myfunctionDF753486: Type: AWS::Lambda::Function Properties: Code: S3Bucket: Ref: AssetParametersdb46 ... Handler: index.main Metadata: aws:cdk:path: my-cdk-stack/my-function/Resource # 👇 using Metadata to specify the absolute lambda path aws:asset:path: /home/bobbyhadz/Desktop/temp/my-cdk-app/src/my-function aws:asset:property: Code

We can see that CDK specified the absolute path of our lambda assets using the Metadata property, that's how CloudFormation knows where to take the assets from prior to uploading them to S3.

When we ran the synth command, AWS CDK created a copy of these assets in the cdk.out directory.

It's important to note that the name of the asset is a hash that's how CDK can determine whether we've made changes to our code.

The other thing to note in our CloudFormation template is that AWS CDK has specified parameters for CloudFormation:

Parameters: AssetParametersdb4686...: Type: String Description: S3 bucket for asset "db46868aa93fbc9..." AssetParametersdb4686...: Type: String Description: S3 key for asset version "db46868aa93fbc9..." AssetParametersdb468...: Type: String Description: Artifact hash for asset "db46868aa93fbc9..."

These parameters include:

  • the name of the s3 bucket that will be storing our assets (Lambda code, etc).
  • the s3 key for the asset
  • the hash for the asset

When we issue the cdk deploy command the CDK CLI will:

  • upload the assets to s3
  • deploy the CloudFormation stack

Let's deploy our stack:

npx aws-cdk deploy

If we look at the Parameters section of the deployed CloudFormation stack, we can see that CDK has automatically provided - the name of the S3 bucket, the S3 key and the name of the hash:

deployed parameters

Even though the parameters are pretty much unreadable we can see:

  • the name of the S3 bucket - cdktoolkit-staging...
  • the name of the zip file in our S3 bucket where the assets are located - assets/db46868aa...

If I open the assets path in my S3 bucket I can see the .zip file:

assets zip

The zip file's hash is equal to the hash of the asset in our cdk.out directory.

The contents are also the same, if I download and extract the zip file, I'll get the index.js file for our Lambda function.

If we then make changes to our Lambda code, the hash of the assets will change and the pointers for the hash and S3 key Parameters in our Stack will also change.

Conclusion #

AWS CDK is an abstraction on top of CloudFormation.

The CDK CLI takes our CDK code and generates the equivalent CloudFormation template.

We first have to bootstrap an environment, which creates:

  • an S3 bucket responsible for storing our assets
  • the necessary IAM roles required to run a deployment

When we synthesize our CDK application, the CDK CLI creates the cdk.out directory where it stores:

  • the CloudFormation template
  • the Assets (i.e. Lambda function code)
  • other meta data

When we issue the deploy command, CDK passes these parameters to our CloudFormation stack:

  • the name of the s3 bucket that will be storing our assets ( Lambda code, etc).
  • the s3 key for the asset
  • the hash for the asset

Before a deployment is run, our assets from the cdk.out directory are deployed to the S3 bucket we bootstrapped.

If we then change our Lambda code, the hash of our assets changes the next time we run the cdk synth command.

Which in turn starts the process from the synthesis step onwards again.

Further Reading #

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.