The Same for everyone: Lambda Function and Code with the same language via AWS CDK

Thumbnail

The AWS CDK has been presented on reInvent 2018. Its mission is to simplify develop infrastructure as code.

There are several other frameworks, as discussed here on the blog in tRick. So there are some competitors… Can you use shiny new CDK also for serverless lambda applications?

Big “Yes” from my side, but read for yourself…

The UseCase

With a Lambda function you do not only need the lambda resource, but also the IAM Role to assume and a S3 Bucket to deploy the code from. You also have the possibility to put code inline into CloudFormation. But that involves a 4K code limit. So this is only an alternative for small code snippets. CDK supports both methods.

Lambda Architecture

Having all those ressources you have to build a zip from all lambda source code including libraries. This zip will be copied to the bucket and deployed to the function.

If you have to deploy without a framework, you could use S3 triggers for that.

Problem Solution with AWS CDK

CDK generates CF templates from TypeScript (or Python, C#, Java). Details in the CDK documentation. Choosing TypeScript because it is the first language.

App Architecture

The Constructs are the reusable components of the application. CDK generates a CloudFormation (cfn) template. With CDK CLI (Command Line Interface) you can manage the template deployment (cdk deploy, cdk destroy , …)

Let`s start a demo to understand the concept. We have prepared the demo code on GitHub: Lambda Simple.

Life Cycle

The example can be run in four simple steps. You have to have node and TypeScript installed beforehand.

The steps have been nicely prepared in the Makefile for you.

  1. Installation and CDK bootstraping: make install.

    The CDK will be installed. Bootstrapping will create a S3 deployment Bucket which you need for ClouodFormation and which will also be used for Lambda.

  2. Download node libs: make init

    Download several node_modules.

  3. Installation: make deploy

    With a CloudFormation template and the zipped lambda subdirectory all needed resources and the function will be deployed. After that step the Lambda function is fully usable.

  4. Delete resources and function: make remove

    All resources will be deleted - never forget to clean up!

CDK Code

Structure

On first glance there are many files. If you look at this simple structure their purpose will be easy to understand:

CDK structure

With cdk.json the application is defined. In this simple case only the reference to the base application cdk-lambda-simple.ts is included. The code is written in *.ts TypeScript. You should run npm run watch in a seperate terminal window, so that all *.ts will be compiled to *.js and type information files *.d.ts.

To understand the CDK you may now just ignore *.js and *.d.ts.

The application cdk-lambda-simple.ts just imports the stack cdk-lambda-simple-stack.ts.

Resource Definition

 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
export class CdkLambdaSimpleStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string) {
    super(scope, id);

    // The code that defines your stack goes here
    new lambda.Function(this, 'HelloHandler', {
      code: lambda.Code.asset(path.join(__dirname,  '../lambda')),
      handler: 'hello.handler',
      runtime: lambda.Runtime.NodeJS810,
      memorySize: 1024
    });
  }
}

The definition of the whole stack now is done in a few simple lines. The IAM role will automatically be generated, just as in the [Serverless Framework](https://serverless.com/.

Development Cycle detail

What will be generated

After installation you generate a diff for information about what will be deployed: cdk diff.

Stack CdkLambdaSimpleStack
The CdkLambdaSimpleStack stack uses assets, which are currently not accounted for in the diff output! See https://github.com/awslabs/aws-cdk/issues/395
IAM Statement Changes
┌───┬─────────────────────────────────┬────────┬────────────────┬──────────────────────────────────┬───────────┐
│   │ Resource                        │ Effect │ Action         │ Principal                        │ Condition │
├───┼─────────────────────────────────┼────────┼────────────────┼──────────────────────────────────┼───────────┤
│ + │ ${HelloHandler/ServiceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:lambda.${AWS::URLSuffix} │           │
└───┴─────────────────────────────────┴────────┴────────────────┴──────────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬─────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                    │ Managed Policy ARN                                                             │
├───┼─────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${HelloHandler/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴─────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See http://bit.ly/cdk-2EhF7Np)

Parameters
[+] Parameter HelloHandler/Code/S3Bucket HelloHandlerCodeS3Bucket4359A483: {"Type":"String","Description":"S3 bucket for asset \"CdkLambdaSimpleStack/HelloHandler/Code\""}
[+] Parameter HelloHandler/Code/S3VersionKey HelloHandlerCodeS3VersionKey07D12610: {"Type":"String","Description":"S3 key for asset version \"CdkLambdaSimpleStack/HelloHandler/Code\""}
[+] Parameter HelloHandler/Code/ArtifactHash HelloHandlerCodeArtifactHash5DF4E4B6: {"Type":"String","Description":"Artifact hash for asset \"CdkLambdaSimpleStack/HelloHandler/Code\""}

Resources
[+] AWS::IAM::Role HelloHandler/ServiceRole HelloHandlerServiceRole11EF7C63
[+] AWS::Lambda::Function HelloHandler HelloHandler2E4FBA4D

Deploy

With cdk deploy the Cloudformation stack and Lambda code is deployed.

Update

If you change the stack or the lambda function code, CDK will notice that. Just check updates with cdk diffand again deploy with cdk deploy.

Changes in Lambda function code will be shown as asset changes:

cdk diff
Stack CdkLambdaSimpleStack
The CdkLambdaSimpleStack stack uses assets, which are currently not accounted for in the diff output! See https://github.com/awslabs/aws-cdk/issues/395
Resources
[~] AWS::Lambda::Function HelloHandler HelloHandler2E4FBA4D
 └─ [~] Metadata
     └─ [~] .aws:asset:path:
         ├─ [-] .cdk.staging/2b8228f7e33311acbcda8a46395ec767
         └─ [+] .cdk.staging/8fcab5493d6556b26fc8a85910c67f6a

Please note

CDK is still in beta - but already usable! Just note, that you must noch mix versions, because at the time many thing are still in flow and are subject to change.

Therefore i have pinned versions to 0.32 in package.json.

"dependencies": {
    "@aws-cdk/aws-lambda": "^0.32.0",
    "@aws-cdk/cdk": "^0.32.0",
    "install": "^0.12.2",
    "npm": "^6.9.0",
    "path": "^0.12.7",
    "source-map-support": "^0.5.9"
  }

Summary

Terraform and Serverless Framework are a good match for multi cloud. When the focus is an AWS, you really should try the CDK!

Already this version 0.32 look really good to me.

Many CloudFormation ressources are abstracted and bundled like Lambda Function and Lambda IAM Role. The difference to the serverless framework is that you have acces to the resource objects directly in the TypeScript code. This makes referencing easy. What do you think?

Code on Github

Lambda Simple

Photo by Søren Astrup Jørgensen on Unsplash

Translations