# jxlxx.org šŸŒ šŸŒš

about projects posts contact

AWS CDK Basics

Talking notes for an AWS CDK workshop.

2022-07-20

What is CDK?

Cloud Development Kit.

Imagineā€¦ You are running some kind of software business.

Youā€™re most likely not self-hosting, and instead using some kind of cloud provider.

Something like: AWS, GCP, Digital Ocean, Linodeā€¦ etc.

What are the kinds of services you need?

Domain NameRoute53
SSLCertificate Manager
CDNCloudFront
Static Assets, etcS3
DatabaseRDS, Dynamo, Aurora, etc
AuthenticationCognito
REST APIAPI Gateway
Business Logic StuffLambda, EC2
Container managementECR

You also probably want a Dev, Stag, and Prod stack.

So a CDK is code that you write, which generates CloudFormation Templates (JSON or YAML), which you push to AWS CloudFormation, and then that builds your AWS infrastructure.

And CloudFormation Templates are ANNOYING.

How to start a CDK project

Get the code: git checkout v1

Every CDK app should be in its own directory.

For this tutorial, all my code is in /BackendGuild. So I did:

mkdir CDKWorkshop

CDK apps can be written in a bunch of languages:

I went with typescript because it has types, everyone can understand it, and it has the most examples and documentation out of all the languages listed by a huuuuge margin.

Globally install aws-cdk and typescript with npm. You also need the aws-cli.

cdk init app --language typescript

Project Structure

lib/name-stack.ts # where you spend most of your time
                  # where the CDK main stack is defined

bin/name.ts # enypoint of the CDK app
            # loads the stack defined in ^^
            # call stuff in lib and instantiate it

package.json  # npm module manifest, build/run scripts etc

cdk.json      # "toolkit" how to run your app

tsconfig.json # typescript configuration

node_modules/ # project dependencies

A note on the lingo

Everything that the init command just created is called a CDK app.

Inside the app there are ā€œstacksā€

Inside the stacks there are ā€œconstructsā€

Simple Example

bin/name.ts

#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkWorkshopStack } from '../lib/cdk-workshop-stack';

const app = new cdk.App();
new CdkWorkshopStack(app, 'CdkWorkshopStack');

All this does is load and instantiate the name stack.

Who cares. Moving on.

Now letā€™s look at lib/name-stack.ts

import * as cdk from 'aws-cdk-lib';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subs from 'aws-cdk-lib/aws-sns-subscriptions';
import * as sqs from 'aws-cdk-lib/aws-sqs';

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

    const queue = new sqs.Queue(this, 'CdkWorkshopQueue', {
      visibilityTimeout: cdk.Duration.seconds(300)
    });

    const topic = new sns.Topic(this, 'CdkWorkshopTopic');

    topic.addSubscription(new subs.SqsSubscription(queue));
  }
}

This does three main things:

  1. Creates an SQS Queue
  2. SNS Topic
  3. Subscribes the 1 to receive any messages published to 2

scope , id, and props

scope is always the first argument in which constructs are created. Usually you just pass in this, because you want to define constructs with the current construct.

id is the local identity of the construct, a unique way to refer to it with its scope.

props are initialization properties. The lambda props accepts properties like runtime, code, handler name.

Our example: creating an S3 bucket

First of all I had to add a couple environment variables:

Then I ran cdk synth to see if everything looked good.

Then I ran cdk bootstrap which creates a ā€œbootstrap stackā€ for the app.

Now I have a bunch of roles, a bucket, etc.

Finally, I do:

cdk deploy

Now lets add some changes:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_s3 as s3 } from 'aws-cdk-lib'

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

    new s3.Bucket(this, 'MyThirdBucket', {
        versioned: true,
        removalPolicy: cdk.RemovalPolicy.DESTROY,
        autoDeleteObjects: true
    });
  }
}

And then run cdk diff:

What else can you do?

Check the docs: class Bucket (construct) Ā· AWS CDK

Important Commands

cdk bootstrap

cdk synth

cdk deploy

cdk diff

cdk deploy --hotswap

cdk watch

note: These commands deliberately introduces drift in CloudFormation stacks in order to speed up deployments.

Drift is when you cloud formation templates donā€™t match your actual stack.

cdk destroy

What is AWS Lambda

AWS Lambda is a serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers.

What do you need:

What is a layer?

A layer is a ZIP archive that contains libraries, a custom runtime, or other dependencies. With layers, you can use libraries in your function without needing to include them in your deployment package.

Letā€™s use lambda

Adding an AWS lambda function

  1. create a directory lambda in the root of the CDK app
  2. add a line to .gitignore to NOT ignore all the .js files in lambda
!lambda/*
  1. add the following js file, lambda/hello.js
exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, CDK! You've hit ${event.path}\n`
  };
};

This is a lambda function that always returns the text ā€œHello, CDK! Youā€™ve hit [url path]ā€

To define an AWS Lambda function you need to use the AWS Construct Library.

The construct library is divided into modules.

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';

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

    // defines an AWS Lambda resource
    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_16_X,    // runtime
      code: lambda.Code.fromAsset('lambda'),  // code loaded from our "lambda" directory
      handler: 'hello.handler'                // file is "hello", function is "handler"
    });
  }
}

Testing Lambda

Using CDK watch

Note: since it is a typescript project and we are using javascript in the lambda function, we have to update cdk.json to not exclude the files

Adding REST trigger

To actually interact with a lambda function from outside of the AWS console you have to give it some kind of trigger.

An obvious example would be, watching for uploads to an S3 bucket.

What we can also do is expose a rest api call that call the lambda function.

The most sensible way to do that would be to use API Gateway, an AWS service to expose public HTTP endpoints.

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigateway';

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

    // defines an AWS Lambda resource
    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_14_X,    // execution environment
      code: lambda.Code.fromAsset('lambda'),  // code loaded from "lambda" directory
      handler: 'hello.handler'                // file is "hello", function is "handler"
    });

    // defines an API Gateway REST API resource backed by our "hello" function.
    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: hello
    });

  }
}

Life Lessons

Questions & Thoughts

Terraform vs. CDKs

Disclaimer: i donā€™t know what Iā€™m talking about.

Terraform uses a JSON-like language to define resources and other data, the HCL, or HashiCorp Configuration Language.

CDKs use code which then generates CloudFormation Templates in Json/yaml.

Terraform works on a lot of platforms, CDK is AWS specific.

Terraform is more reusable. You can ā€œreuseā€ CDK code but you cannot ā€œcreate your own modulesā€.

Cuelang would be interesting for this kinda thing I THINK

Disclaimer: i donā€™t know what Iā€™m talking about here either.

CUE (Configure Unify Execute)

Not a ā€œfullā€ programming language. Itā€™s kinda like Jsonnet.

CUE is written in Go.

The CUE language has an unusual property which sets it apart from many other languages and formats - types and values are the same.Ā Not the same as only same type of structure, like JSON and JSON Schema,Ā but actually the same.

An aws example I found:

Take a cue to supercharge your configurations

Can create reusable definitions.

Fun Fact

I went to a golang meetup last week and this guy pronounced fmt as fumpt šŸ˜³